专栏文章

题解:P2827 [NOIP 2016 提高组] 蚯蚓

P2827题解参与者 7已保存评论 9

文章操作

快速查看文章及其快照的属性,并进行相关操作。

当前评论
9 条
当前快照
1 份
快照标识符
@miqbkqie
此快照首次捕获于
2025/12/04 02:07
3 个月前
此快照最后确认于
2025/12/04 02:07
3 个月前
查看原文
Jayne(老师,不敢@)和 Lyzc0dr的激烈讨论,得出来一种新做法。

首先我们明白一个不等式 x1px1x2px2x_1-\lfloor px_1 \rfloor \ge x_2 \lfloor px_2 \rfloor,具体证明过程请看 dbxxx的TJ
根据这个不等式,我们可以考虑维护三个队列,而不必维护一个优先队列,因为三个队列始终保持满足单调性,无需使用优先队列(此处和其他 TJ 相同)。
然后根据此思路即可拿到所有 q=0q = 0 的分,接下来为了解决 q>0q > 0,通常方法都是计个 tagtag,加入队列时把两段都减掉一个 qqtagtag 加上一个 qq
考虑到一条在第 ii 时刻加入的长度为 lenlen 蚯蚓,如果在第 jj 时刻被拿出来砍,因为它一共经历了 ji1j - i - 1 次切割,一次切割长度加 qq,所以总长度是 q×(ji1)+lenq \times (j - i - 1) + len可以在常数时间内算出,不必打 tagtag 标记,只需多存个加入时间。

那么具体做法请看代码:
CPP
#include <bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int,int>
const int maxn=2e5+10;
int n,m,Q,u,v,t,a[maxn];
queue<pii>q[4];//ABC三个队列
int get_max_len(int time){//取出最长的蚯蚓
	int x=-1e9,y=-1e9,z=-1e9;
	if(!q[1].empty())x=q[1].front().first+Q*(time-1-q[1].front().second);
	if(!q[2].empty())y=q[2].front().first+Q*(time-1-q[2].front().second);
	if(!q[3].empty())z=q[3].front().first+Q*(time-1-q[3].front().second);
	//分别取出三个队列队首
	int idx=1LL,tmp=0LL;//idx表示取出来哪一个队列的队首,tmp表示最大的队首
	if(x>=y && x>=z) tmp=x,idx=1;
	if(y>=x && y>=z) tmp=y,idx=2;
	if(z>=x && z>=y) tmp=z,idx=3;
	//更新tmp和idx
	q[idx].pop();//弹出
	return tmp;
}
signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	cin>>n>>m>>Q>>u>>v>>t;
	for(int i=1;i<=n;i++) cin>>a[i];
	sort(a+1,a+n+1);//正序排序(从小到大)
	for(int i=n;i>=1;i--) q[1].push({a[i],0});//倒序加入(从大到小)
	for(int i=1;i<=m;i++){
		int len=get_max_len(i),x,y;
		x=len*u/v,y=len-x;//分段
		if(i%t==0) cout<<len<<" ";//输出
		q[2].push({x,i}),q[3].push({y,i});//同其他TJ,加入B,C两个队列,始终保持单调
	}
	cout<<"\n";//换行
	for(int i=1;;i++){
		if(q[1].empty() && q[2].empty() && q[3].empty()) break;//三个队列都空了就停止
		int tmp=get_max_len(m+1);//继续获取最大的蚯蚓
		if(i%t==0) cout<<tmp<<" ";//输出
	}
	return 0;
}

评论

9 条评论,欢迎与作者交流。

正在加载评论...