P2827-蚯蚓【队列】

前言

早年一直拿堆过不了,结果发现要用队列
在这里插入图片描述


正题

题目链接:https://www.luogu.com.cn/problem/P2827


题目大意

n n 条蚯蚓,每次选取最长的一条,切成 x p \lfloor x*p\rfloor x x p x-\lfloor x*p\rfloor 的两段,然后其余蚯蚓变长 q q

求每次切开蚯蚓的长度和最后所以蚯蚓的长度。


解题思路

先不考虑变长

和合并果子的思路很像,我们发现如果从大到小切切出来的也是从大到小的,所以我们开三个队列,第一个队列装初始的蚯蚓,然后切出来的左边装到第二个队列,右边装到第三个队列,这样每个队列的长度也是单调的,之后每次取出三个队头里最长的来剪掉就好了。

考虑变长,初始的蚯蚓第 i i 次长度为 x + i q x+i*q ,那么我们直接当做所有长度都是 x + i q x+i*q 的蚯蚓,然后将第 i i 次加入的蚯蚓长度变为 x i q x-i*q 即可。

时间复杂度 O ( n + m ) O(n+m)


c o d e code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
using namespace std;
const ll N=7e6+10;
ll n,m,q,u,v,t,a[N],q1[N*2],q2[N*2],q3[N*2];
int main()
{
	scanf("%lld%lld%lld%lld%lld%lld",&n,&m,&q,&u,&v,&t);
	for(ll i=1;i<=n;i++)
		scanf("%lld",&a[i]);
	sort(a+1,a+1+n);
	memset(q1,-127,sizeof(q1));
	memset(q2,-127,sizeof(q2));
	memset(q3,-127,sizeof(q3));
	ll h1,h2,h3,t1,t2,t3;
	h1=h2=h3=1;t1=t2=t3=0;
	for(ll i=n;i>=1;i--)
		q1[++t1]=a[i];
	for(ll i=1;i<=m;i++){
		ll l,r,x;
		if(q1[h1]>=q2[h2]&&q1[h1]>=q3[h3])x=q1[h1++];
		else if(q2[h2]>=q1[h1]&&q2[h2]>=q3[h3])x=q2[h2++];
		else x=q3[h3++];
		x+=(i-1)*q;l=x*u/v;r=x-l;
		q2[++t2]=l-q*i;q3[++t3]=r-q*i;
		if(i%t==0) printf("%lld ",x);
	}
	printf("\n");
	for(ll i=1;i<=m+n;i++){
		ll x;
		if(q1[h1]>=q2[h2]&&q1[h1]>=q3[h3])x=q1[h1++];
		else if(q2[h2]>=q1[h1]&&q2[h2]>=q3[h3])x=q2[h2++];
		else x=q3[h3++];
		if(i%t==0)printf("%lld ",x+m*q);
	}
}

附上远古时期堆的代码

90 p t s   c o d e 90pts\ code

#include<cstdio>
#include<algorithm>
#define N 100010
#define M 7000010
using namespace std;
int n,a[N+M],num,m,q,t,addl,u,v;
double p;
void up(int x)
{
	while(x>1&&a[x>>1]<a[x])
	{
		swap(a[x],a[x>>1]);
		x>>=1;
	}
}
void down(int x)
{
	int y;
	while((x<<1)<=num&&a[x<<1]>a[x]
		  ||((x<<1)|1)<=num&&a[(x<<1)|1]>a[x])
	{
		y=x<<1;
		if(a[y]<a[y|1]&&((x<<1)|1)<=num) y|=1;
		swap(a[x],a[y]);
		x=y;
	}
}
int main()
{
	scanf("%d%d%d%d%d%d",&n,&m,&q,&u,&v,&t);
	p=(double)u/v;
	for(int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
		num++;
		up(num);
	}
	int k=1;
	for (int i=1;i<=m;i++)
	{
		int k1,k2;
		a[1]=a[1]+addl;
		k1=(double)a[1]*p;
		k2=a[1]-k1;
		if(k==t)
		{printf("%d ",a[1]);k=0;}
		a[1]=k1-addl-q;down(1);
		a[++num]=k2-addl-q;
		k++;
		up(num);
		addl+=q;
	}
	k=1;
	printf("\n");
	while(num)
	{
		if(k==t) printf("%d ",a[1]+addl),k=0;
		swap(a[1],a[num]);
		num--;
		k++;
		down(1);
	}
}

猜你喜欢

转载自blog.csdn.net/Mr_wuyongcong/article/details/105328690
今日推荐