洛谷原题链接
关于题目不多赘述
初始想法
因为每次需要取出最长的一条蚯蚓进行操作,所以下意识就想到了堆
第一问在取出是每次取出,第二问则是最终结果
但是如何处理每秒都会增长的q?
开设一个Add变量,表示所有蚯蚓的增长量,每次取出一条蚯蚓就将原量加上Add再进行处理, 放回堆中时还要再减去Add
因为切割会影响增长,所以每次切割完后放回堆钟的蚯蚓都要再减去q
总复杂度为O((n+m)log(n+m))只能得65分
看了题解后的想法
我们会发现蚯蚓的切割具有单调性:一只蚯蚓切割后会分为|px|和x-|px|两个部分,对于其中的任意一个部分,在某一时刻切割出的那只蚯蚓必然会比在它之后切割出来的蚯蚓要长
反证法可证明
考虑记录三个队列,分别存储未切割过的蚯蚓和切割成的两只蚯蚓,每次将蚯蚓插入对应的队尾。根据我们上面推论得出的单调性,每次取出三个队头的最大值即可,蚯蚓长度的增加和上述堆做法的处理方式相同,这样的总复杂为O(n+m)
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int inf = ~1u>>1;
const int maxn = 1e5 + 5, maxm = 7e6 + 5;
int n, m, q, u, v, t, Add;
int Q[3][maxm], qt[3], qw[3];
inline int get_num() {
int num; char ch;
while((ch = getchar()) < '0' || ch > '9');
num = ch - '0';
while((ch = getchar()) >= '0' && ch <= '9')
num = (num << 3) + (num << 1) + ch - '0';
return num;
}
inline void put_num(int x) {
if(x > 9) put_num(x/10);
putchar(x%10 + 48);
}
inline bool cmp(const int &x, const int &y) {
return x > y;
}
inline int get_max() {
int ret = -inf, k;
for(int i = 0; i < 3; ++i) {
if(qt[i] < qw[i] && ret < Q[i][qt[i]+1]) {
ret = Q[i][qt[i]+1], k = i;
}
}
qt[k]++;
return ret;
}
int main() {
n = get_num(); m = get_num(); q = get_num();
u = get_num(); v = get_num(); t = get_num();
for(int i = 1; i <= n; ++i) Q[0][++qw[0]] = get_num();
sort(Q[0]+1, Q[0]+qw[0]+1, cmp);
for(int i = 1; i <= m; ++i) {
int x = get_max() + Add;
if(i%t == 0) {
put_num(x);
putchar(i+t>m ? '\n' : ' ');
}
int l = (ll)x * u / v,
r = x - l;
Q[1][++qw[1]] = l - Add - q;
Q[2][++qw[2]] = r - Add - q;
Add += q;
}
if(t > m) putchar('\n');
int tmp = n+m;
for(int i = 1; i <= tmp; ++i) {
int x = get_max() + Add;
if(i%t == 0) {
put_num(x);
if(i+t <= tmp) {
putchar(' ');
}
}
}
return 0;
}