Description

【NOIP2016提高组复赛】蚯蚓_NOIP

Solution

这题打暴力,用堆来做,理论上是可以拿80分,所以比赛还是打暴力好。
但是,正解又短又机智。
我们假设x1>x2。
那么x1肯定会在x2之前就被剪断。
设x1被剪成p1和q1,p1=⌊px1⌋,q1=x1−⌊px1⌋
设x2被剪成p2和q2,p2=⌊px2⌋,q2=x2−⌊px2⌋
我们可以得到一个很显然的结论,p1>p2,q1>q2,也就是说p1一定会在p2之前被剪断,q1一定会在q2之前被剪断。
我们来简单的证明一下:
假设x1剪断之后到剪断x2经过了i的时间,
那么此时x2=x2+i∗q,p1=⌊px1⌋+i∗q,q1=x1−⌊px1⌋+i∗q
剪断x2之后p2=⌊p(x2+i∗q)⌋,q2=x2+i∗q−⌊p(x2+i∗q)⌋
我们先比较一下p1和p2的大小关系:
我们如果不考虑取整的话,p1−p2=p(x1−x2)+q∗(i−i∗p),因为p是小于1的,所式子一定是大于0的。
p2和q2的大小关系同理。
得证。
那么知道了这个结论之后要怎么去用呢。
我们设三个队列,一个a[0],a[1],a[2]。
a[0]预先存原序列的从大到小的排序。
a[1]存px的从大到小排序
a[2]存x-px的从大到小排序
那么每次取出最大的队首,然后拆掉存到a[1]和a[2]中,根据结论这样一定合法。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=7100007;
typedef long long ll;
ll i,j,k,t,n,m,ans,p,q,u,v,da,x,y,tt;
ll a[3][maxn],l[3],r[3];
bool cmp(int x,int y){return x>y;}
int main(){
freopen("earthworm.in","r",stdin);
freopen("earthworm.out","w",stdout);
scanf("%d%d%d%d%d%d",&n,&m,&q,&u,&v,&tt);
fo(i,1,n+m)a[0][i]=a[1][i]=a[2][i]=-0x7fffffff;
fo(i,1,n)scanf("%lld",&a[0][i]);
sort(a[0]+1,a[0]+1+n,cmp);
l[0]=1,r[0]=n;l[1]=l[2]=1;r[1]=r[2]=0;
fo(i,1,m){
da=-0x7fffffff;
fo(j,0,2){
if(a[j][l[j]]>da)da=a[j][l[j]],k=j;
}
t=da+(i-1)*q;
l[k]++;
if(i%tt==0)printf("%lld ",t);
x=t*u/v;y=t-x;
a[1][++r[1]]=x-i*q;
a[2][++r[2]]=y-i*q;
}
printf("\n");
fo(i,1,n+m){
da=-0x7fffffff;
fo(j,0,2){
if(a[j][l[j]]>da)da=a[j][l[j]],k=j;
}
t=da+m*q;
l[k]++;
if(i%tt==0)printf("%lld ",t);
}
}