【NOIP2016提高组复赛】蚯蚓

时间:2021-08-26 19:06:54

Description

【NOIP2016提高组复赛】蚯蚓

Solution

这题打暴力,用堆来做,理论上是可以拿80分,所以比赛还是打暴力好。
但是,正解又短又机智。
我们假设 x1>x2
那么x1肯定会在x2之前就被剪断。
x1 被剪成 p1q1p1=px1,q1=x1px1
x2 被剪成 p2q2p2=px2,q2=x2px2
我们可以得到一个很显然的结论, p1>p2q1>q2 ,也就是说 p1 一定会在 p2 之前被剪断, q1 一定会在 q2 之前被剪断。
我们来简单的证明一下:
假设x1剪断之后到剪断x2经过了i的时间,
那么此时 x2=x2+iq,p1=px1+iqq1=x1px1+iq
剪断x2之后 p2=p(x2+iq),q2=x2+iqp(x2+iq)
我们先比较一下 p1p2 的大小关系:
我们如果不考虑取整的话, p1p2=p(x1x2)+q(iip) ,因为p是小于1的,所式子一定是大于0的。
p2q2 的大小关系同理。
得证。
那么知道了这个结论之后要怎么去用呢。
我们设三个队列,一个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);
}
}