[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;
}