1.计算系数
(factor.cpp/c/pas)
【问题描述】
给定一个多项式(ax + by)k,请求出多项式展开后xn ym项的系数。
【输入】
输入文件名为 factor.in。
共一行,包含 5 个整数,分别为a,b,k,n,m,每两个整数之间用一个空格隔开。
【输出】
输出文件名为 factor.out。
输出共 1 行,包含一个整数,表示所求的系数,这个系数可能很大,输出对10007 取
模后的结果。
【输入输出样例】
factor.in factor.out
1 1 3 1 2 3
【数据范围】
对于 30%的数据,有0≤k≤10;
对于 50%的数据,有a = 1,b = 1;
对于 100%的数据,有0≤k≤1,000,0≤n, m≤k,且n + m = k,0≤a,b≤1,000,000。
//模了两个数相乘可能除不尽,要乘逆元;ans=c(k,n)*a^n*b^m;
#include<iostream>
#include<cstdio>
using namespace std;
const int mod=10007;
int a1,b1,k,n,m,d;
long long mull(int a,int b)
{
long long rt=0;
for(;b;b>>=1,a=(a+a)%mod)
{
if(b&1)rt=(rt+a)%mod;
}
return rt;
}
long long mpow(int a,int b)
{
long long rt=1;
for(;b;b>>=1,a=(1ll*a*a)%mod)
{
if(b&1)rt=(1ll*rt*a)%mod;
}
return rt;
}
void exgcd(int a,int b,long long &x,long long &y)
{
if(b==0)
{
d=a;
x=1;
y=0;
return ;
}
else
{
long long x0,y0;
exgcd(b,a%b,x0,y0);
x=y0;
y=x0-(a/b)*y0;
}
}
int inverse( int a) {
long long x, y;
exgcd( a, mod, x, y );
return (x % mod + mod) % mod;
}
int main()
{
freopen("factor.in","r",stdin);
freopen("factor.out","w",stdout);
cin>>a1>>b1>>k>>n>>m;
int he=k-n;
long long sk=1,she=1;
for(int i=1;i<=k;i++)
{
if(i<=he)she=mull(she,i);
if(i>n) sk=mull(sk,i);
}
int ha=inverse(she);
int xiang=sk*ha;
cout<<mpow(a1,n)*mpow(b1,m)%mod*xiang%mod;
return 0;
}
2.聪明的质监员
【输入】
输入文件 qc.in。
第一行包含三个整数 n,m,S,分别表示矿石的个数、区间的个数和标准值。
接下来的 n 行,每行2 个整数,中间用空格隔开,第i+1 行表示i 号矿石的重量wi 和价
值vi 。
接下来的 m 行,表示区间,每行2 个整数,中间用空格隔开,第i+n+1 行表示区间[Li,
Ri]的两个端点Li 和Ri。注意:不同区间可能重合或相互重叠。
【输出】
输出文件名为 qc.out。
输出只有一行,包含一个整数,表示所求的最小值。
【输入输出样例】
qc.in qc.out
5 3 15
1 5
2 5
3 5
4 5
5 5
1 5
2 4
3 3
10
【输入输出样例说明】
当 W 选4 的时候,三个区间上检验值分别为20、5、0,这批矿产的检验结果为25,此
时与标准值S 相差最小为10。
【数据范围】
对于 10%的数据,有1≤n,m≤10;
对于 30%的数据,有1≤n,m≤500;
对于 50%的数据,有1≤n,m≤5,000;
对于 70%的数据,有1≤n,m≤10,000;
对于 100%的数据,有1≤n,m≤200,000,0 < wi, vi≤106,0 < S≤1012,1≤Li≤Ri≤n。
//二分参数W,每次check,记录满足条件的val和个数的前缀,然后暴力把检查值算出,ans1是大于s和s最接近的与s的差,ans2是小于s和s最接近的与s的差,ll从0开始(有可能不设W,就可以得到s)。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
int n,m,s,w[200005],v[200005],l[200005],r[200005],sum[200005],tot[200005];
long long check(int k)
{
memset(sum,0,sizeof(sum));
memset(tot,0,sizeof(tot));
for(int i=1;i<=n;i++)
if(w[i]>k)sum[i]=sum[i-1]+v[i],tot[i]=tot[i-1]+1;
else sum[i]=sum[i-1],tot[i]=tot[i-1];
int ans=0;
for(int i=1;i<=m;i++)
ans+=(sum[r[i]]-sum[l[i]-1])*(tot[r[i]]-tot[l[i]-1]);
return ans;
}
int main()
{
cin>>n>>m>>s;int ma=0;
for(int i=1;i<=n;i++)
{scanf("%d%d",&w[i],&v[i]);
ma=max(ma,w[i]);
}
for(int i=1;i<=m;i++)
{
scanf("%d%d",&l[i],&r[i]);
}
int ll=0,rr=ma;
long long ans1=1e15,ans2=1e15;
while(ll<=rr)
{
int mid=(ll+rr)/2;
long long temp=check(mid);
if(temp>s)
{
ans1=temp-s;
ll=mid+1;
}
else if(temp==s)
{
printf("0");
return 0;
}
else
{
ans2=s-temp;
rr=mid-1;
}
}
cout<<min(ans2,ans1);
return 0;
}
3.3.观光公交
(bus.cpp/c/pas)
【问题描述】
风景迷人的小城 Y 市,拥有n 个美丽的景点。由于慕名而来的游客越来越多,Y 市特
意安排了一辆观光公交车,为游客提供更便捷的交通服务。观光公交车在第0 分钟出现在1
号景点,随后依次前往2、3、4……n 号景点。从第i 号景点开到第i+1 号景点需要Di 分钟。
任意时刻,公交车只能往前开,或在景点处等待。
设共有 m 个游客,每位游客需要乘车1 次从一个景点到达另一个景点,第i 位游客在
Ti 分钟来到景点Ai,希望乘车前往景点Bi(Ai<Bi)。为了使所有乘客都能顺利到达目的地,
公交车在每站都必须等待需要从该景点出发的所有乘客都上车后才能出发开往下一景点。
假设乘客上下车不需要时间。
一个乘客的旅行时间,等于他到达目的地的时刻减去他来到出发地的时刻。因为只有一
辆观光车,有时候还要停下来等其他乘客,乘客们纷纷抱怨旅行时间太长了。于是聪明的司
机ZZ 给公交车安装了k 个氮气加速器,每使用一个加速器,可以使其中一个Di 减1。对于
同一个Di 可以重复使用加速器,但是必须保证使用后Di 大于等于0。
那么 ZZ 该如何安排使用加速器,才能使所有乘客的旅行时间总和最小?
【输入】
输入文件名为 bus.in。
第 1 行是3 个整数n, m, k,每两个整数之间用一个空格隔开。分别表示景点数、乘客数
和氮气加速器个数。
第 2 行是n-1 个整数,每两个整数之间用一个空格隔开,第i 个数表示从第i 个景点开
往第i+1 个景点所需要的时间,即Di。
第 3 行至m+2 行每行3 个整数Ti, Ai, Bi,每两个整数之间用一个空格隔开。第i+2 行表
示第i 位乘客来到出发景点的时刻,出发的景点编号和到达的景点编号。
【输出】
输出文件名为 bus.out。共一行,包含一个整数,表示最小的总旅行时间。
【输入输出样例】
bus.in bus.out
3 3 2
1 4
0 1 3
1 1 2
5 2 3
10
【输入输出样例说明】
对 D2 使用2 个加速器,从2 号景点到3 号景点时间变为2 分钟。
公交车在第 1 分钟从1 号景点出发,第2 分钟到达2 号景点,第5 分钟从2 号景点出发,
第7 分钟到达3 号景点。
第 1 个旅客旅行时间 7-0 = 7 分钟。
第 2 个旅客旅行时间 2-1 = 1 分钟。
第 3 个旅客旅行时间 7-5 = 2 分钟。
总时间 7+1+2 = 10 分钟。
【数据范围】
对于 10%的数据,k=0;
对于 20%的数据,k=1;
对于 40%的数据,2 ≤ n ≤ 50,1 ≤ m≤ 1,000,0 ≤ k ≤ 20,0 ≤ Di ≤ 10,0 ≤ Ti ≤ 500;
对于 60%的数据,1 ≤ n ≤ 100,1 ≤ m≤ 1,000,0 ≤ k ≤ 100,0 ≤ Di ≤ 100,0 ≤ Ti ≤ 10,000;
对于 100%的数据,1 ≤ n ≤ 1,000,1 ≤ m ≤ 10,000,0 ≤ k ≤ 100,000,0 ≤ Di ≤ 100,
0 ≤ Ti ≤ 100,000。
//最主要的就是加速,怎么加;
1.加从i-1到i的路程,只会影响i站要下车的乘客;
2..如果车到达第i站的时间大于从第i站上车的最后一个乘客上车的时间,那么加速i-1到i所需时间,就会影响从第i站上车的乘客
#include<iostream>
#include<cstdio>
using namespace std;
int n,m,k,sum[1005],d[1005],t[100005],get[1005],dada[1005],last[1005],b[10005],a[10005];
int main()
{
cin>>n>>m>>k;
for(int i=2;i<=n;i++)
scanf("%d",&d[i]);
for(int i=1;i<=m;i++)
{scanf("%d%d%d",&t[i],&a[i],&b[i]);
last[a[i]]=max(last[a[i]],t[i]);//第i站最后一个乘客上车时间
sum[b[i]]++;//第i 站下车的乘客数}
for(int i=2;i<=n;i++)
get[i]=max(last[i-1],get[i-1])+d[i];//到达第i站所需时间
long long ans=0;
for(int i=1;i<=m;i++)ans+=get[b[i]]-t[i];//先求不用加速器时乘客到达各自目的地所需时间的和while(k>0)
{int maxn=0,temp=0;
for(int i=n;i>=2;i--)
{
dada[i]=sum[i];//dada[]修改第i-1站到第i站的时间会影响到乘客的数量
if(get[i]>last[i])
{dada[i]+=dada[i+1];}
}
for(int i=2;i<=n;i++)
{
if(dada[i]>maxn&&d[i]>0)
{maxn=dada[i];//maxn记录修改哪段最多影响到的人数temp=i;//记录修改哪段}
}
ans-=maxn;k--;d[temp]--;//修改
for(int i=temp;i<=n;i++)
{get[i]=max(get[i-1],last[i-1])+d[i];//更新}
}
cout<<ans;
return 0;}