题目描述:https://www.luogu.org/problemnew/show/P2827
解析:
暴力做法:建立优先队列,每次要切的时候从队首弹出切完再插进去。考虑怎么处理q:被切的蚯蚓不能增长等同于相对于其他蚯蚓负增长了q,于是想到记录当前总增长的长度sum(即t*q)。每次从队首取出元素的时候加上sum,计算完答案后再减去加过q的sum。时间复杂度O(mlog2n).
正解:发现长蚯蚓相较于短蚯蚓被切后仍然是更长的,具有单调性。于是想到另外开两个数组来记录被切蚯蚓的第一段与被切蚯蚓的第二段。每次要切的时候从取三个队首的最大值。切完之后分别加入第二个队列和第三个队列。
细节:1.注意精度问题 2.注意数组开的大小,队首和队尾会不停的往后移 3.注意清空队列时要清成-0x3f3f3f,因为如果清成0,当队列为空时,队首元素为0,但其他队首元素可能为负
附上代码:
#include<cstdio> #include<algorithm> #include<cmath> #include<queue> #include<cstring> using namespace std; typedef long long LL; const int maxn=1e6+5; int n,m,q,u,v,t; LL q1[10*maxn],q2[10*maxn],q3[10*maxn]; int h1,t1,h2,t2,h3,t3; LL sum=0; priority_queue<LL> ans; inline LL read() { LL ret=0,f=1;char ch=getchar(); while (ch<'0'||ch>'9') {if (ch=='-') f=-f;ch=getchar();} while (ch>='0'&&ch<='9') ret=ret*10+ch-'0',ch=getchar(); return ret*f; } inline LL max(LL a,LL b){ return a>b?a:b; } inline bool cmp(const LL &a,const LL &b){ return a>b; } inline LL getmax(){ LL ans1,ans2,ans3; if(h1<=t1) ans1=q1[h1]+sum; else ans1=0; if(h2<=t2) ans2=q2[h2]+sum; else ans2=0; if(h3<=t3) ans3=q3[h3]+sum; else ans3=0; if(ans1>=ans2&&ans1>=ans3){ h1++;return ans1; } if(ans2>=ans1&&ans2>=ans3){ h2++;return ans2; } if(ans3>=ans1&&ans3>=ans2){ h3++;return ans3; } } int main(){ scanf("%d%d%d%d%d%d",&n,&m,&q,&u,&v,&t); for(int i=1;i<=n;i++) q1[i]=read(); sort(q1+1,q1+n+1,cmp); h1=1,t1=n,h2=h3=1; double r=u*1.0/v*1.0; for(register int i=1;i<=m;i++){ LL now=getmax(); LL res1=floor(r*(now*1.0)),res2=now-res1; sum+=q; res1-=sum,res2-=sum; q2[++t2]=res1,q3[++t3]=res2; if(i%t==0) printf("%lld ",now); } printf("\n"); for(register int i=h1;i<=t1;i++) ans.push(q1[i]); for(register int i=h2;i<=t2;i++) ans.push(q2[i]); for(register int i=h3;i<=t3;i++) ans.push(q3[i]); for(register int i=1;ans.size();i++){ if(i%t==0) printf("%lld ",ans.top()+sum); ans.pop(); } return 0; }