题解 P2827 【蚯蚓】

题目链接

Solution 蚯蚓

题目大意:一开始有(n)只蚯蚓,你操作(m)次。每次抓最长的一只,记长度为(x),切成(lfloor px floor),(x-lfloor px floor)两只放回去,同时除这两只外的所有蚯蚓长度增加(q),问每次切断蚯蚓的长度,(m)次操作后所有蚯蚓的长度

队列


首先我们来解决除新增外集体增加(q)的问题,我们可以维护一个增量(delta),表示所有的蚯蚓的长度都要增加(delta),新增的两只蚯蚓不加(q),我们就将它长度减(q)后再处理即可,因此在处理中可能有负数

不难想到一个简单粗暴的模拟思路,用一个大根堆,每次取最大的切了后丢回去同时维护增量(delta)。但是这样会带一个(log),无法承受

关键在于切断后新增的两条蚯蚓都比原来的短,因此我们每次取出来的蚯蚓长度是递减的(不考虑增量(delta)),用序列合并这题思路,用一个队列(Q_1)存储原来的(n)条蚯蚓(排个序就好),(Q_2)存储切成(lfloor px floor)的蚯蚓,(Q_3)存储切成(x-lfloor px floor)的蚯蚓,每次从三个队列队头取最大值,切成的蚯蚓分别丢进(Q_2),(Q_3)维护(delta)即可

#include <algorithm>
#include <cstdio>
#include <cctype>
#include <queue>
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 100;
inline int read(){
	int x = 0;char c = getchar();
	while(!isdigit(c))c = getchar();
	while(isdigit(c))x = x * 10 + c - '0',c = getchar();
	return x;
}
queue<ll> Q[4];
int val[maxn],n,m,q,u,v,t;
ll delta;
inline int findmax(){
	int res = 0;
	for(int i = 1;i <= 3;i++)
		if(!Q[i].empty() && (!res || Q[i].front() > Q[res].front()))res = i;
	return res;
}
inline ll cut(ll x){return 1ll * u * x / v;}
inline void solve(int tim){
	ll x = Q[findmax()].front();Q[findmax()].pop();
	if(tim % t == 0)printf("%lld ",x + delta);
	Q[2].push(cut(x + delta) - delta - q);Q[3].push(x - cut(x + delta) - q);
	delta += q;
}
int main(){
	n = read(),m = read(),q = read(),u = read(),v = read(),t = read();
	for(int i = 1;i <= n;i++)val[i] = read();
	sort(val + 1,val + 1 + n);
	for(int i = n;i >= 1;i--)Q[1].push(val[i]);
	for(int i = 1;i <= m;i++)solve(i);
	putchar('
');
	for(int i = 1;i * t <= n + m;i++){
		for(int j = 1;j <= t - 1;j++)
			Q[findmax()].pop();
		printf("%lld ",Q[findmax()].front() + delta);
		Q[findmax()].pop();
	}
	putchar('
');
	return 0;
}
原文地址:https://www.cnblogs.com/colazcy/p/11711460.html