[Noip2016]蚯蚓

[Noip2016]蚯蚓

一.前言

​ 连肝三篇题解,是窒息的感觉……题目链接

二.思路

​ 一开始以为是裸的优先队列板子题……但是是我天真了。不管对于甚么数据结构,每次改变所有蚯蚓的长度肯定是够呛的。记录一个应有的增长量,如果一个蚯蚓没被切过,直接在初始长度上加上增长量就算得出来。

​ 不失一般性,被切也可以用类似的方法解决。根据初二物理第一课,物体的运动是相对的,所以蚯蚓的增长也是相对的(狗头)。所以每切一条,分成的两个小蚯蚓等同于缩短了一次。那么在这两个蚯蚓的初始长度上面减去一次就好。最后加回来还是一样的。

​ 但是切掉的蚯蚓实际上具有单调性,也就是,早切早大,内卷(错乱)。同样是被切,早切早大……这是基于上面的加法推出的,能被早切,证明原本就比较长,同样乘以一个常数后也比较长,每次被切又都是初始长度减一个相同量,自然早切早大。给出数学的简单证明。

\[\because a\ge b\\ \therefore ak\ge bk\\ \therefore ak-i\ge bk-i\\ \therefore ak-i+sum\ge bk-i+sum \]

i 为一次增长量,sum 为要输出答案时的总增加量,a,b表示初始长度,k 是切的常数,感性理解一下吧。

​ 用三个队列记录一下没有被切过的,切过的左半截,切过的右半截。每次从三个队首中挑一个最大的切就好。

三.CODE

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<fstream>
#include<cmath>
#include<queue>
using namespace std;
int read(){
	char ch=getchar();
	int res=0,f=1;
	for(;ch<'0'||ch>'9';ch=getchar())if(ch=='-')f=-1;
	for(;ch>='0'&&ch<='9';ch=getchar())res=res*10+(ch-'0');
	return res*f;
}
const int _inf=-1<<30;
int n,m,q,u,v,t,sum,a[100005];
queue<int>a1,a2,a3,ans;
inline int get(){
	int x=a1.empty()?_inf:a1.front(),y=a2.empty()?_inf:a2.front(),z=a3.empty()?_inf:a3.front();
	if(x>=y&&x>=z){
		a1.pop();
		return x+sum;
	}
	if(y>=x&&y>=z){
		a2.pop();
		return y+sum;
	}
	if(z>=x&&z>=y){
		a3.pop();
		return z+sum;
	}
}
int main(){
	n=read();m=read();q=read();u=read();v=read();t=read();
	for(int i=1;i<=n;++i)a[i]=read();
	sort(a+1,a+n+1);
	for(int i=n;i>=1;--i)a1.push(a[i]);
	for(int i=1;i<=m;++i){
		int now=get();
		if(i%t==0)printf("%d ",now);
		a2.push(1LL*now*u/v-q-sum);
		a3.push(now-1LL*now*u/v-q-sum);
		sum+=q;
	}
	printf("\n");
	int cnt=0;
	while(!a1.empty()||!a2.empty()||!a3.empty()){
		++cnt;
		int now=get();
		if(cnt%t==0)printf("%d ",now);
	}
	return 0;
} 
posted @ 2020-08-15 21:30  clockwhite  阅读(162)  评论(0编辑  收藏  举报