题目梗概
n只蚯蚓,有一个神刀手他每t秒会选择一个长度最大的蚯蚓x,切成px和x-px两段(如果出现0也视为存活),每秒除了被切的蚯蚓之外的所有蚯蚓都会增长q.
询问,m秒内,每t秒被切断的蚯蚓切断前的长度。
m秒后,所有蚯蚓的长度。
蚯蚓长度向下取整 [2.9]->[2] [3.1]->[3]
思考
惭愧的是,去年在考场这个题目我居然奇迹般的爆0了。
所以题目要怎么写呢?
- 首先每次取最长的蚯蚓这个操作,一定需要优先队列(不然你每次操作之后再去排序一遍吗?)
- 其次我们可以用一个Lazy标记,在每次堆中元素取出的时候进行操作,就不再需要对每个蚯蚓进行加和操作了。
- 如果我们把切割后的两个蚯蚓看成两个序列,那么它们都呈现出单调递减的性质。(先切的蚯蚓一定长,后切的蚯蚓一定短。在比率一定的情况下,前者一定大于后者)
- 所以,我们需要一个大根堆和两个队列来维护。
感觉题目思维难度还是有的,一开始我只写了一个60分的做法(大根堆维护),在瞄了一眼题解区之后,发现大佬们还是太强了Orz。
对了,请不要忘了读入。算法的时间复杂度是(N+M)
#include <cstdio> #include <algorithm> #include <cmath> typedef long long ll; const int N = 1e5+5,M =7e6+5; const int Max = 2147483647; int n,m,q,u,v,t,Lazy; int Q[3][M],Head[3],Tail[3]; //读入 inline int Read() { char ch; int res = 0; bool f = true; while (((ch = getchar()) < '0' || ch > '9') && ch != '-'); if (ch == '-') f = false; else res = ch - '0'; while ((ch = getchar()) >= '0' && ch <= '9') res = (res << 3) + (res << 1) + ch - '0'; return f? res : -res; } //输出 inline void Out(int x) { if (x < 0) x = -x, putchar('-'); if (x > 9) Out(x / 10); putchar(x % 10 + 48); } inline bool CMP(const int &x,const int &y) { return x>y; } //求三个队列的最大值 inline int GetMax(){ int res = - Max,k; for(int i=0;i<3;++i) if(Head[i]<Tail[i] && res<Q[i][Head[i]+1]) res = Q[i][Head[i]+1],k=i; Head[k]++; return res; } int main(){ n = Read(); m = Read(); q = Read(); u = Read(); v = Read(); t = Read(); for(int i=1;i<=n;++i) Q[0][++Tail[0]] = Read(); std::sort(Q[0]+1,Q[0]+Tail[0]+1,CMP); for(int i=1;i<=m;++i){ int x = GetMax() + Lazy; if(i%t==0) Out(x),putchar(i + t > m ? '\n' : ' '); int l = (ll)x * u / v,r = x - l; Q[1][++Tail[1]] = l - Lazy - q; Q[2][++Tail[2]] = r - Lazy - q; Lazy+=q; } if(t>m) putchar('\n'); int ans = n+m; for(int i=1;i<=ans;++i){ int x = GetMax() + Lazy; if(i%t==0) { Out(x); if(i+t<=ans) putchar(' '); } } return 0; }