标签:
1.计算系数
本人比较耿直,没有想到递推的组合数公式,而是用了快速幂求逆元。
复杂度O(Klog10007)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 8 //variable// 9 int a,b,k,n,m,mod=10007; 10 11 //function prototype// 12 int qpower(int,int,int); 13 14 //solve// 15 int main(){ 16 scanf("%d%d%d%d%d",&a,&b,&k,&n,&m); 17 int ans=1; 18 ans=(ans*qpower(a,n,mod))%mod; 19 ans=(ans*qpower(b,m,mod))%mod; 20 for (int i=1;i<=k;++i){ 21 ans=(ans*i)%mod; 22 } 23 for (int i=1;i<=n;++i){ 24 ans=(ans*qpower(i,mod-2,mod))%mod; 25 } 26 for (int i=1;i<=m;++i){ 27 ans=(ans*qpower(i,mod-2,mod))%mod; 28 } 29 printf("%d\n",ans); 30 return 0; 31 } 32 33 int qpower(int a,int b,int m){ 34 int ret=1; 35 a%=m; 36 while (b){ 37 if (b&1){ 38 ret=(ret*a)%m; 39 } 40 b>>=1; 41 a=(a*a)%m; 42 } 43 return ret; 44 }
2.聪明的质检员
我们看出,随着基准值W的增大,检验值Y减小。于是想到二分。
满足wj≥W的数和这种数的数量都满足前缀和性质。于是对于二分到的W,可以O(N+M)求出每个区间的Y。
总复杂度O((N+M)logN)
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 8 //variable// 9 int n,m,l[200100],r[200100],w[200100],v[200100],tot[200100]; 10 long long s,sum[200100]; 11 12 //function prototype// 13 bool judge(int); 14 void calc_ans(void); 15 long long calc_y(int); 16 17 //solve// 18 int main(){ 19 scanf("%d%d%lld",&n,&m,&s); 20 for (int i=1;i<=n;++i){ 21 scanf("%d%d",w+i,v+i); 22 } 23 for (int i=1;i<=m;++i){ 24 scanf("%d%d",l+i,r+i); 25 } 26 calc_ans(); 27 return 0; 28 } 29 30 void calc_ans(){ 31 int left=1,right=1000000; 32 while (left<=right){ 33 int mid=left+right>>1; 34 if (judge(mid)){ 35 left=mid+1;//sum>=s 36 }else{ 37 right=mid-1;//sum<s 38 } 39 } 40 long long yl=calc_y(left),yr=calc_y(right); 41 printf("%lld\n",min(s-yl,yr-s)); 42 } 43 44 bool judge(int x){ 45 long long y=calc_y(x); 46 return (y>=s); 47 } 48 49 long long calc_y(int x){ 50 tot[0]=0;sum[0]=0ll; 51 for (int i=1;i<=n;++i){ 52 sum[i]=sum[i-1]; 53 tot[i]=tot[i-1]; 54 if (w[i]>=x){ 55 sum[i]+=(long long)v[i]; 56 ++tot[i]; 57 } 58 } 59 long long y=0ll; 60 for (int i=1;i<=m;++i){ 61 y+=((long long)tot[r[i]]-tot[l[i]-1])*(sum[r[i]]-sum[l[i]-1]); 62 } 63 return y; 64 }
3.观光公交
一直到60%的数据都是可以DP的。真正的正解是贪心。
首先考虑如何计算结果,我们令maxArrivei表示从i点出发的人,Ti的最大值,也就是最迟的到达时间,没人从i出发则为0。再令enteri表示到达i点的最早时间,那么
enteri=Max(enteri−1,maxArrivei−1)+Di−1 (3)
那么对于从Ai点到Bi点的旅客i,他用的时间为
enterBi−Ti (4)
那么我们消耗的总时间就是
Summi=1(enterBi−Ti)=(Summi=1enterBi)−(Summ i=1Ti) (5)
由于减去的是一个常量,所以我们只要得到Summi=1enterBi的最小值即可。
设第i个点有cnti个人以该点为终点。那么答案也就是
Sumni=1cnti∗enteri (6)
接下来我们进一步观察enter的计算方法,可以发现3式等价于
enteri=Maxi−1 j=1(maxArrivej+Si−Sj) (7)
其中Si表示1点到i点的距离。
我们令Vi=maxArrivei−Si那么
enteri=Maxi−1 j=1(Vj)+Si (8)
那么考虑减少一个Di,会产生什么影响。可以发现所有的j≤i的点的S,V都没有变化,所有j>i的点,Sj=Sj−1,Vj=Vj+1由于每个点的enteri值都取决于前面最大的V值,如果有多个最大的话,不妨让它被最后一个决定。那么考虑一个点的V值,他假如要决定后面一些enter值的话,必须满足之前的所有V值都不比他大。 我们可以令决定了后面的一些enter值的点分别为a0,a1,a2...ap−1,那么显然他们的V值也是单调不减的(由于条件)。同时易知每个ai必然决定了连续的一个子序列。也就是讲整个序列分成了一块一块,每块都有一个vai决定。ai决定了ai+1∼ai+1这一段的enter值。
我们可以发现,假如我们减少ai∼ai+1−1这些点中一个的D值,那么ai前面的块 完全不受影响,ai+1和之后的块的点x,Maxx−1 j=1(Vj)+了1,但是Sx−了1,所以enter值不变,同时也没有任何其它的影响。所以每个块之间是独立的。 考虑块[l,r],被[l,r]之前一个数决定,那么我们将Dl−1−1,可以将结果减少Sumi=r i=lcnti,同时由于将[l,r]中的数的V值变大了,[l,r]可能被分成几块,那样之后的操作就比之前的 操作烂了(因为每次只能减少一个块的Sumi=r i=lcnti,而块变小了),也就是说对于每个块来说,一次操作能取得的总时间减少量只会越来越少。 那么考虑当前能节省最大时间的块,如果不取他,那么由于之后的操作都比他要劣,所以随便把之后的一个操作换成他就能更优,而那样就不是最优解了。所以一定要取他。
其实只需要开一个堆,每次从堆里取出能减少最大时间的那个块[l,r],消耗k将Dl−1减小,那么有3种情况。
(1):要么Dl−1被减成0,那么就只能减Dl了,将[l+1,r]放进堆
(2):要么k被减完,结束。
(3):要么减到一半时,[l,r]中的一个数变成了新的可以决定后面enter值的数,那么[l,r]分裂。
(1)和(3)都最多出现n次,(2)最多出现1次,每次操作复杂度O(logn)。所以总复杂度 O(m+nlogn)
然而不开堆暴力貌似也是可以的。
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 7 //variable// 8 int n,m,k,a[10010],b[10010],c[10010],t[10010]; 9 int r[1010],get[1010],off[1010],in[1010],leave[1010],d[1010],s[1010]; 10 long long ans; 11 12 //solve// 13 int main(){ 14 scanf("%d%d%d",&n,&m,&k); 15 for (int i=1;i<n;++i) scanf("%d",d+i); 16 for (int i=0;i<m;++i){ 17 scanf("%d%d%d",t+i,a+i,b+i); 18 off[b[i]]++;in[a[i]]++; 19 leave[a[i]]=max(leave[a[i]],t[i]); 20 } 21 for (int i=2;i<=n;++i){ 22 get[i]=max(get[i-1],leave[i-1])+d[i-1]; 23 } 24 int p=1; 25 for (int i=1;i<=n;++i){ 26 while (p<n&&leave[p]<get[p]||p<=i) p++; 27 r[i]=p; 28 s[i]=s[i-1]+off[i]; 29 } 30 while (k){ 31 int maxp=0,station; 32 for (int i=1;i<n;++i) 33 if (s[r[i]]-s[i]>maxp&&d[i]>0){ 34 maxp=s[r[i]]-s[i]; 35 station=i; 36 } 37 if (maxp==0) break; 38 int maxt=0x7fffffff; 39 for (int j=station+1;j<n&&leave[j]<get[j];++j) 40 maxt=min(maxt,get[j]-leave[j]); 41 int maxDecK=min(d[station],min(maxt,k)); 42 k-=maxDecK; 43 d[station]-=maxDecK; 44 for (int j=station+1;j<=r[station];++j) 45 get[j]=max(get[j-1],leave[j-1])+d[j-1]; 46 for (int j=p=station;j<r[station];++j){ 47 while (p<n&&leave[p]<get[p]||p<=j) p++; 48 if (p>=r[j]) break; 49 r[j]=p; 50 } 51 } 52 int ans=0; 53 for (int i=0;i<m;++i){ 54 ans+=(long long)(get[b[i]]-t[i]); 55 } 56 cout<<ans<<endl; 57 return 0; 58 }
标签:
原文地址:http://www.cnblogs.com/ZXTLFDeAR/p/4823954.html