1 条题解
-
0
题解
「蚯蚓」模拟的核心是维护当前长度的最大值,并把它按比例拆成两段。直接使用优先队列会超时,因此代码将三个来源的队列分离,并用指针和懒加值来维护:
- 初始化:读入初始长度数组
a
并按降序排序。b
、c
分别存放拆分后产生的两段。 - 懒标记:由于每经过一次操作,所有蚯蚓都会统一加上
q
,程序在取出最大值时临时加上(i-1)*q
,并在把新段放入b
、c
时再减去当前的增量,等到后续取出时补回即可。 - 多路合并:用三个指针 指向目前仍未取走的段,每次比较三者的真实长度(考虑懒加值)选出最大的那条蚯蚓。把长度
l
按比例拆成l*u/v
和l - l*u/v
两条,分别放进b
、c
的末尾。 - 输出:每经过
t
次操作输出一次当前取出的长度;最后还要把所有剩余的段(包括b
、c
中的)按取出的顺序补齐输出,同样需要补上总共增加的m*q
。
由于每条蚯蚓最多被拆一次,整个过程只在数组上前移指针,时间复杂度 \(O((n+m)\ log(n+m))\)≈\(O(n+m)\),可以满足数据范围。
#include<cstdio> using namespace std; long long n,m,q,u,v,t,a[200000],b[7100000],c[7100000],qq[200000],la,ra,lb,rb,lc,rc,i,l,aa,bb,p; void sort(int l,int r) { int i=l,j,k=l,mid=(l+r)/2; j=mid+1; if(l==r) { qq[l]=a[l]; return; } sort(l,mid); sort(mid+1,r); while(i<=mid&&j<=r) { if(qq[i]>=qq[j]) { a[k]=qq[i]; i++; } else { a[k]=qq[j]; j++; } k++; } while(i<=mid) { a[k]=qq[i]; i++; k++; } while(j<=r) { a[k]=qq[j]; j++; k++; } for(i=l;i<=r;i++) qq[i]=a[i]; } main() { scanf("%lld%lld%lld%lld%lld%lld",&n,&m,&q,&u,&v,&t); la=1; ra=n; lb=1; lc=1; for(i=1;i<=n;i++) scanf("%lld",&a[i]); sort(1,n); for(i=1;i<=m;i++) { l=-1000000000000; if(ra>=la&&a[la]>=l) { l=a[la]; p=1; } if(rb>=lb&&b[lb]>=l) { l=b[lb]; p=2; } if(rc>=lc&&c[lc]>=l) { l=c[lc]; p=3; } l=l+(i-1)*q; aa=l*u/v; bb=l-aa; if(i%t==0) printf("%lld ",l); rb++; b[rb]=aa-i*q; rc++; c[rc]=bb-i*q; if(p==1) la++; if(p==2) lb++; if(p==3) lc++; } printf("\n"); for(i=1;i<=n+m;i++) { l=-1000000000000; if(ra>=la&&a[la]>=l) { l=a[la]; p=1; } if(rb>=lb&&b[lb]>=l) { l=b[lb]; p=2; } if(rc>=lc&&c[lc]>=l) { l=c[lc]; p=3; } l=l+m*q; if(i%t==0) printf("%lld ",l); if(p==1) la++; if(p==2) lb++; if(p==3) lc++; } }
- 初始化:读入初始长度数组
- 1
信息
- ID
- 3237
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 4
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者