明天NOIP了,祝自己rp++!
Description
Input
Output
Sample Input
3 3 2
Sample Output
6 6 6 5 5 4 4 3 2 2
Solution
解法一
题目要求多次询问最大值,很明显可以用二叉堆求解。
用一个优先队列保存每只蚯蚓,每次取最大值然后砍成两个数放回去。
至于处理每只蚯蚓$+=q$,遍历每个元素显然不现实。转变思路,设$add$表示到目前为止总共增加的长度,由于运动是相互的,除了新砍出来的两只以外所有蚯蚓增长$q$等价于将新砍出来的蚯蚓减去$q$。所以我们在每次$pop$时将拿出来的蚯蚓长度$+=add$,$push$时两条蚯蚓长度$-=add$即可。
时间复杂度$O((n+m)log_2(n+m))$,预期得分$65$,卡常优秀加上处理时输出能得$85$分。其实考场上暴力$85$分已经很可以了$qwq$
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N = 1e5 + 10; 4 const int M = 7e6 + 10; 5 int n, m, q, u, v, t, num, add, now, e1, e2; 6 double p; 7 priority_queue<int, vector<int>, less<int> > Q; 8 9 inline int read() { 10 int res = 0, flag = 1; 11 char c = getchar(); 12 for(; !isdigit(c); c = getchar()) if(c == '-') flag = -1; 13 for(; isdigit(c); c = getchar()) res = (res<<3) + (res<<1) + (c^48); 14 return res * flag; 15 } 16 17 int main() { 18 n = read(), m = read(), q = read(), u = read(), v = read(), t = read(); 19 p = (double)u/v; 20 for(register int i = 1; i <= n; i++) { 21 register int k = read(); 22 Q.push(k); 23 } 24 for(register int i = 1; i <= m; i++) { 25 now = Q.top() + add; 26 Q.pop(); 27 e1 = floor((double)now*p), e2 = now - e1; 28 add += q; 29 e1 -= add, e2 -= add; 30 Q.push(e1), Q.push(e2); 31 if(!(i%t)) printf("%d ", now); 32 } 33 printf("\n"); 34 for(int i = 1; !Q.empty(); i++) { 35 if(!(i%t)) printf("%d ", Q.top() + add); 36 Q.pop(); 37 } 38 return 0; 39 }
解法二
连二叉堆都不需要。
引理:
对于先砍的蚯蚓分成的两段中的任意一段,它一定比后切掉的蚯蚓长。
证明:
反证法。
假设存在这样一只长度为$a_i$的蚯蚓,它被砍后$T$秒钟砍的那只蚯蚓分成的两段长度最大。设这只蚯蚓$T$秒前的长度为$a_j$。则:
$\cdot pa_i+Tq≤(Tq+a_j)p$
展开,得$pa_i+Tq≤Tpq+pa_j$。
因为当$a_i$被砍时一定有$a_i>a_j$,
所以$pa_i>pa_j$。
又因为$0<p<1$,
所以$pa_i+Tq>Tpq+pa_j$,与之前结论$pa_i+Tq≤Tpq+pa_j$矛盾,故假设不成立,原命题成立。
证毕。
于是可以考虑建立三个队列,其中$now$存储原始蚯蚓,$cut1$和$cut2$分别存储切割成的两只蚯蚓,根据引理,输出时每次取三个队头的最大值即可。蚯蚓长度增量处理方法同上。时间复杂度$O(n+m)$。
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int INF = ~0U>>1; 4 const int M = 7e6 + 10; 5 int cut1[M],now[M],cut2[M]; 6 int n, m, q, u, v, t, add, h, h1, h2, t0, t1, t2; 7 double p; 8 9 inline int read() { 10 int res = 0, flag = 1; 11 char c = getchar(); 12 for(; !isdigit(c); c = getchar()) if(c == '-') flag = -1; 13 for(; isdigit(c); c = getchar()) res = (res<<3) + (res<<1) + (c^48); 14 return res * flag; 15 } 16 17 inline bool cmp(const int &x,const int &y){ 18 return x > y; 19 } 20 21 int main(){ 22 n = read(), m = read(), q = read(), u = read(), v = read(), t = read(); 23 p = (double)u/v; 24 for(t0 = 1; t0 <= n; t0++) now[t0] = read(); 25 t0--; 26 t1 = t2 = 0; 27 h = h1 = h2 = 1; 28 sort(now+1, now+t0+1, cmp); 29 int top; 30 for(register int i = 1; i <= m; i++){ 31 if(h > t0) { 32 if(cut1[h1] > cut2[h2]) top = cut1[h1++]; 33 else top = cut2[h2++]; 34 } 35 else if(now[h]>=cut1[h1] && now[h]>=cut2[h2]) top = now[h], h++; 36 else if(cut1[h1]>=cut2[h2] && now[h]<=cut1[h1]) top = cut1[h1], h1++; 37 else top = cut2[h2], h2++; 38 top += add; 39 int e1 = floor((double)top*p), e2 = top - e1; 40 add += q; 41 e1 -= add, e2 -= add; 42 cut1[++t1] = e1, cut2[++t2] = e2; 43 if(!(i%t)) printf("%d ", top); 44 } 45 printf("\n"); 46 int i=1; 47 while(h<=t0 || h1<=t1 || h2<=t2) { 48 int flag, Max = -INF; 49 if(h <= t0 && now[h] > Max) Max = now[h], flag = 1; 50 if(h1 <= t1 && cut1[h1] > Max) Max = cut1[h1], flag = 2; 51 if(h2 <= t2 && cut2[h2] > Max) Max = cut2[h2], flag = 3; 52 if(flag == 1) h++; 53 else if(flag == 2) h1++; 54 else h2++; 55 if(!(i%t)) printf("%d ", Max + add); 56 i++; 57 } 58 return 0; 59 }