看完题目以后,我马上想到了用优先队列,但是这里面m<=7*10^6,用优先队列会超时。
所以开始挖掘题目的隐藏条件。
经过观察发现,切蚯蚓都是在同一个地方切,切完以后分为了比例相同的两个小段。因为题目说每次切断最长的蚯蚓,那么我们就可以猜想先切掉的蚯蚓分成的两个小段分别比后切的蚯蚓分成的两个小段更长(当然也有可能一样长)。
证明:
设先切掉的蚯蚓分成了l1,r1,后切掉的分成了l2,r2
1.如果蚯蚓不会变长(也就是一起变长),那么证明肯定成立。(l1 >= l2,r1 >= r2)
2.回到原题,当切第一条蚯蚓的时候,第二条蚯蚓增加了q,而后面把q分给l2,r2;当切第二条蚯蚓的时候,l1,r1都增加q。很明显有q >= q * p(0 <= p <= 1)
证毕。
所以只需要再开两个队列,分别存储l和r
对于每秒都会增长的长度,只需要把增加的长度用一个数先存起来,使用的时候再加上即可
时间复杂度O(nlogn+m)
代码(有几个细节需要注意,最好自己打一遍)
#pragma GCC optimize("Ofast")
#include <cstdio>
#include <cstring>
#include <iostream>
#include <cstdlib>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = 1e5 + 10, M = 7e6 + 10;
int n, m, q, u, v, T;
int a[N], h1[M], h2[M], l, l1, r1, l2, r2;
double p;
bool cmp(int p1, int p2) { return p1 > p2; }
int main() {
cin >> n >> m >> q >> u >> v >> T;
p = double(u) / v;
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
sort (a + 1, a + n + 1, cmp);
l = l1 = l2 = 1; r1 = r2 = 0;
int now = 0;
for (int i = 1; i <= m; i++) {
int maxx, pos = -1;
if (l <= n && pos == -1) maxx = a[l], pos = 0;//查找最大值
if (l1 <= r1 && (pos == -1 || maxx < h1[l1])) maxx = h1[l1], pos = 1;
if (l2 <= r2 && (pos == -1 || maxx < h2[l2])) maxx = h2[l2], pos = 2;
if (!pos) l++; else if(pos == 1) l1++; else l2++;
maxx += now; now += q;//把maxx变成真实长度
int d1 = (int)((double)maxx * p), d2 = maxx - d1;
h1[++r1] = d1 - now, h2[++r2] = d2 - now; //d1,d2都是真实的长度,存到队列里面要减去now
if (i % T == 0) printf("%d ", maxx);
}
puts("");
for (int i = 1; i <= n + m; i++) {
int maxx, pos = -1;//把队列合并,类似归并排序
if (l <= n && pos == -1) maxx = a[l], pos = 0;
if (l1 <= r1 && (pos == -1 || maxx < h1[l1])) maxx = h1[l1], pos = 1;
if (l2 <= r2 && (pos == -1 || maxx < h2[l2])) maxx = h2[l2], pos = 2;
if (!pos) l++; else if(pos == 1) l1++; else l2++;
if (i % T == 0) printf("%d ", maxx + now);
}
puts("");
return 0;
}