​传送女仆​

(???女仆专属服务)

蚯蚓(NOIP2016)_NOIP2016


这道题,写的难度并不大。

至于难不难想,呵呵,我已经忘了。

我们手写三个队列。

第一个用于存放没有切过的蚯蚓。

第二个用于存放被切过的较长的半个蚯蚓。

第三个用于存放被切过的较短的半个蚯蚓。

我们做的时候,先把第一个排一下序,然后就以时间为遍历对象。

然后每次取出一个最大的,然后切过后在放入第二个和第三个。

那么怎么取最大的?

取三个队列的头部,比较一下即可。

那么第一个队列的头显然是最大的,那么第二个和第三个的头部为什么是最大的呢?

因为我们知道无论是切过还是没切过的蚯蚓每一个时间单位都要增长同样的单位长度。

所以他们的相对长度是不变的。

又因为我们每次挑的都是最大的一个,而且切割比例是相同的,所以先切的一定比后切的长。

最后一个问题就是我们怎么处理增长的长度?

这个,只要取出来的时候处理一下即可。

首先我们以时间为枚举对象,所以我们有当前的时间。

对于第一个队列的蚯蚓,那显然一直没切过,直接加就好了。

那么对于第二个第三个队列,因为我们每一个时间单位都要切,所以他们的小标就是他们进入的时间,这样就可以计算了。

代码如下:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int n,m,q,u,v,t;
int h1,h2,h3,t1,t2,t3;
int q1[8000001],q2[8000001],q3[8000001];
int cmp(int a,int b){
return a>b;
}
int pop1(int time){
int top1=-1,top2=-1,top3=-1;
if(h1<=t1){
top1=q1[h1]+(time-1)*q;
}
if(h2<=t2){
top2=q2[h2]+(time-h2-1)*q;
}
if(h3<=t3){
top3=q3[h3]+(time-h3-1)*q;
}
int k=1;
if(top1<top2){
k=2;
}
if(top3>max(top1,top2)){
k=3;
}
switch(k){
case 1:h1++;return top1;break;
case 2:h2++;return top2;break;
case 3:h3++;return top3;break;
}
}
void push1(int x){
int p1=1LL*x*u/v;
int p2=x-p1;
if(p1<p2){
swap(p1,p2);
}
q2[++t2]=p1;
q3[++t3]=p2;
}
int main(){
scanf("%d%d%d%d%d%d",&n,&m,&q,&u,&v,&t);
for(int i=1;i<=n;i++){
scanf("%d",&q1[i]);
}
sort(q1+1,q1+n+1,cmp);
h1=1;
h2=1;
h3=1;
t1=n;
t2=0;
t3=0;
int top;
for(int i=1;i<=m;i++){
top=pop1(i);
if(i%t==0){
printf("%d ",top);
}
push1(top);
}
printf("\n");
for(int i=1;i<=n+m;i++){
top=pop1(m+1);
if(i%t==0){
printf("%d ",top);
}
}
return 0;
}