洛谷 P2827 蚯蚓
首先最容易想到的
85分 优先队列
#include <iostream>
#include <cstdio>
#include <queue>
#include <cmath>
using namespace std;
priority_queue<int> qy;
int main(){
int n,m,t,q;
double u,v,p;
scanf("%d %d %d %lf %lf %d",&n,&m,&q,&u,&v,&t);
p=u/v;
for(int i=0;i<n;++i)
{
int d;
scanf("%d",&d);
qy.push(d);
}
int ans=0;
for(int i=1;i<=m;++i)
{
int d=qy.top()+ans;//要先还原,不然计算d1 d2会出错
qy.pop();
if(!(i%t))
printf("%d ",d);
int d1=floor(p*double(d)),d2=d-d1;
d1-=ans;
d2-=ans;
d1-=q;
d2-=q;
//减掉加上的ans,由于d1 d2少加一次q,先减掉一次
//printf("%d %d %d\n",d,d1,d2);
qy.push(d1);
qy.push(d2);
ans+=q;
}
printf("\n");
for(int i=1;i<=n+m;++i)
{
int d=qy.top();
if(!(i%t))
printf("%d ",d+ans);
qy.pop();
}
printf("\n");
return 0;
}
看完题解…emmm
解释摘了aiyougege的题解
关键点:
发现此题中隐含的单调性.
发现先被切掉的蚯蚓分成的蚯蚓一定比后切掉的蚯蚓分成的蚯蚓大.
证明:
假设这两只蚯蚓分别为a,b,其中a>b.
那么它被切成a1,a2,t秒后, b被切成了b1,b2
此时a1,a2的长度为p*a+q*t
,(1-p)*a+q*t
而b1,b2的长度却为p*(b+q*t)
, (1-p)*(b+q*t)
易看出a1>b1,a2>b2 .
也就是说根本不需要用一个堆来维护, 它本来就具有一定单调性.
那么就可以将这两堆依次存储, 加上还没被切过的蚯蚓.每次要切时在这三堆里面选择最大的, 切完再依次放回去. 所以这么做时间复杂度为O(m)O(m).再优化一下细节基本上就没问题了.
结论: 善于发现题目中隐含的单调性.
Tip:有些细节需要仔细考虑不然会很惨
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
#define N 7100005
int n,m,k,t;
double u,v,p;
struct T
{
int h,t;
int q[N];
}q[4];
bool cmp(int a,int b)
{
return a>b;
}
void push(int d,int x)
{
q[d].t++;
q[d].q[q[d].t]=x;
//printf("%d %d\n",q.t,q.q[q.t]);
}
void pop(int d)
{
q[d].h++;
}
int max()
{
int d1=1,d2;
d2=q[2].q[q[2].h]>q[3].q[q[3].h]?2:3;
if(q[1].h>q[1].t)//注意有可能q[1]为空 后面是0 而q[2] q[3] 会出现负数
return d2;
d1=q[1].q[q[1].h]>q[d2].q[q[d2].h]?d1:d2;
return d1;
}
int main(){
//freopen("a.txt","r",stdin);
//freopen("b.txt","w",stdout);
q[1].h=1,q[1].t=0;
q[2].h=1,q[2].t=0;
q[3].h=1,q[3].t=0;
scanf("%d %d %d %lf %lf %d",&n,&m,&k,&u,&v,&t);
p=u/v;
for(int i=0;i<n;++i)
{
int l;
scanf("%d",&l);
push(1,l);
}
sort(q[1].q+1,q[1].q+n+1,cmp);
int ans=0;
for(int i=1;i<=m;++i)
{
int d=max();
int x=q[d].q[q[d].h]+ans;
if(!(i%t))
printf("%d ",x);
pop(d);
int a=floor(double(x)*p),b=x-a;
//printf("%d %d %d\n",x,a,b);
a-=ans,b-=ans;
a-=k,b-=k;
if(a>b)
{
push(2,a);
push(3,b);
}
else
{
push(2,b);
push(3,a);
}
ans+=k;
}
printf("\n");
for(int i=q[2].h;i<=q[2].t;++i)
{
push(1,q[2].q[i]);
}
for(int i=q[3].h;i<=q[3].t;++i)
{
push(1,q[3].q[i]);
}
sort(q[1].q+q[1].h,q[1].q+q[1].t+1,cmp);
int y=0;
for(int i=q[1].h;i<=q[1].t;++i)
{
y++;
if(!(y%t))
printf("%d ",q[1].q[i]+ans);
pop(1);
}
return 0;
}
加优化
三个堆都具有单调性,每一次比较三个堆顶就能得到最大值
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;
#define N 7100005
int n,m,k,t;
double u,v,p;
struct T
{
int h,t;
int q[N];
}q[4];
bool cmp(int a,int b)
{
return a>b;
}
void push(int d,int x)
{
q[d].t++;
q[d].q[q[d].t]=x;
//printf("%d %d\n",q.t,q.q[q.t]);
}
void pop(int d)
{
q[d].h++;
}
int max()//三个都要判空 七种情况 无比麻烦...
{
int d1,d2,d3;
d1=q[2].q[q[2].h]>q[3].q[q[3].h]?2:3;
d2=q[1].q[q[1].h]>q[3].q[q[3].h]?1:3;
d3=q[2].q[q[2].h]>q[1].q[q[1].h]?2:1;
if(q[1].h>q[1].t)
{
if(q[2].h>q[2].t)//1 2为空
return 3;
if(q[3].h>q[3].t)//1 3为空
return 2;
return d1;//1为空
}
if(q[2].h>q[2].t)
{
if(q[3].h>q[3].t)//2 3为空
return 1;
return d2;//2为空
}
if(q[1].h>q[1].t)//3为空
return d3;
return q[d1].q[q[d1].h]>q[d2].q[q[d2].h]?d1:d2;//都不为空 可以任意两个比较
}
int main(){
//freopen("a.txt","r",stdin);
//freopen("b.txt","w",stdout);
q[1].h=1,q[1].t=0;
q[2].h=1,q[2].t=0;
q[3].h=1,q[3].t=0;
scanf("%d %d %d %lf %lf %d",&n,&m,&k,&u,&v,&t);
p=u/v;
for(int i=0;i<n;++i)
{
int l;
scanf("%d",&l);
push(1,l);
}
sort(q[1].q+1,q[1].q+n+1,cmp);
int ans=0;
for(int i=1;i<=m;++i)
{
int d=max();
int x=q[d].q[q[d].h]+ans;
if(!(i%t))
printf("%d ",x);
pop(d);
int a=floor(double(x)*p),b=x-a;
//printf("%d %d %d\n",x,a,b);
a-=ans,b-=ans;
a-=k,b-=k;
if(a>b)
{
push(2,a);
push(3,b);
}
else
{
push(2,b);
push(3,a);
}
ans+=k;
}
printf("\n");
for(int i=1;i<=m+n;++i)//直接利用单调性 找三个队列最大值并出队
{
int d=max();
int x=q[d].q[q[d].h]+ans;
pop(d);
if(!(i%t))
printf("%d ",x);
}
return 0;
}