【noip2016】蚯蚓(单调性+队列)
题目贼长
大意是你有n个线段,每一秒你要拿出来最长的一个线段切成两段长度为[p*u](向下取整)和u-[p*u]两段(其中u是线段长,p是一个大于0小于1的实数)没被切的线段长度加q(0<q<200)。问m秒后的n+m条线段的长度(1≤n≤100000,1<=m<=7000000)
题解
乍一看是堆,可是堆被卡了。
我们建三个队列分别装最初的线段,和被切出来的两种线段。可以发现任何时候,一个队列里的线段长度单调递减,最长的线段,就从这三个队列里取出第一个比较就行。
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cmath> 5 #include<algorithm> 6 using namespace std; 7 const int N=10001000; 8 long long n,m,q,u,v,t,z[N],qu1[N],qu2[N],qu3[N],h1,h2,h3,t1,t2,t3,cnt2[N],cnt3[N]; 9 bool cmp(long long x,long long y){ 10 return x>y; 11 } 12 int main(){ 13 scanf("%lld%lld%lld%lld%lld%lld",&n,&m,&q,&u,&v,&t); 14 for(long long i=1;i<=n;i++){ 15 scanf("%lld",&z[i]); 16 } 17 sort(z+1,z+1+n,cmp); 18 for(long long i=1;i<=n;i++){ 19 qu1[++t1]=z[i]; 20 } 21 h1=h2=h3=1; 22 for(long long i=1;i<=m;i++){ 23 long long a=qu1[h1]+(i-1)*q; 24 if(h1>t1)a=0; 25 long long b=qu2[h2]+(i-cnt2[h2]-1)*q; 26 if(h2>t2)b=0; 27 long long c=qu3[h3]+(i-cnt3[h3]-1)*q; 28 if(h3>t3)c=0; 29 long long d=max(a,max(b,c)); 30 if(d==a)h1++; 31 else if(d==b)h2++; 32 else h3++; 33 long long e=(long long)d*u/v; 34 long long f=d-e; 35 qu2[++t2]=e; 36 qu3[++t3]=f; 37 cnt2[t2]=cnt3[t3]=i; 38 if(i%t==0)printf("%lld ",d); 39 } 40 printf("\n"); 41 for(long long i=1;i<=m+n;i++){ 42 long long a=qu1[h1]+m*q; 43 if(h1>t1)a=0; 44 long long b=qu2[h2]+(m-cnt2[h2])*q; 45 if(h2>t2)b=0; 46 long long c=qu3[h3]+(m-cnt3[h3])*q; 47 if(h3>t3)c=0; 48 long long d=max(a,max(b,c)); 49 if(d==a)h1++; 50 else if(d==b)h2++; 51 else h3++; 52 if(i%t==0)printf("%lld ",d); 53 } 54 return 0; 55 }