LUOGU P2827 蚯蚓 (noip 2016)
解题思路
第一眼以为是一个二叉堆,直接上优先队列60分。。。后来听ztz11说有单调性,新加入的蚯蚓一定比原先在的蚯蚓长度长,开三个队列,分别放原先的长度,切掉后大的那一半,切掉后小的那一半。假设原先的第一个数为x1,第二个数为x2,x1>x2,那么取出x1后大的那一半记做x1*p(假设p>1/2) ,第二个数此时加q,第二次再将第二个数拿出来,大的那一半就是(x2+q)*p=x2*p+q*p,而原先第一个数大的那一半变成了x1*p+q,因为x1>x2,p<0,所以符合单调性。所以只需要每次取出最大的切,然后分成两半分别放入第二个与第三个队列。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
typedef long long LL;
using namespace std;
const int MAXN = 1e5+5;
const LL inf = 1e18+5;
const int MAXM = 7e6+5;
inline int rd(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
while(isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();}
return x*f;
}
int n,m,q,u,v,t;
LL ans[MAXM],a[MAXN];
queue<LL> Q[4];
inline bool cmp(int x,int y){
return x>y;
}
int main(){
// freopen("rand.txt","r",stdin);
// freopen("A.txt","w",stdout);
n=rd();m=rd();q=rd();u=rd();v=rd();t=rd();
for(register int i=1;i<=n;i++) a[i]=rd();
sort(a+1,a+1+n,cmp);
for(register int i=1;i<=n;i++) Q[1].push(a[i]);
for(register int i=1;i<=m;i++){
LL x=-inf,y=-inf,z=-inf;
if(Q[1].size()) x=Q[1].front();
if(Q[2].size()) y=Q[2].front();
if(Q[3].size()) z=Q[3].front();
LL mx=x;int r=1;
if(y>mx) mx=y,r=2;
if(z>mx) mx=z,r=3;Q[r].pop();
mx+=(LL)(i-1)*q;ans[i]=mx;
LL now=mx;mx=mx*u/v;now=now-mx;
Q[2].push(max(now,mx)-(LL)i*q);
Q[3].push(min(now,mx)-(LL)i*q);
}
for(register int i=t;i<=m;i+=t) printf("%lld ",ans[i]);
puts("");int yy=1;
for(register int i=1;i<=n+m;i++){
LL x=-inf,y=-inf,z=-inf;
if(Q[1].size()) x=Q[1].front();
if(Q[2].size()) y=Q[2].front();
if(Q[3].size()) z=Q[3].front();
LL mx=x;int r=1;
if(y>mx) mx=y,r=2;
if(z>mx) mx=z,r=3;Q[r].pop();
// cout<<mx+(LL)q*m<<" ";
if(yy<t) {yy++;continue;}
yy=1;printf("%lld ",mx+(LL)m*q);
}
return 0;
}