前言
早年一直拿堆过不了,结果发现要用队列
正题
题目链接:https://www.luogu.com.cn/problem/P2827
题目大意
有nnn条蚯蚓,每次选取最长的一条,切成⌊x∗p⌋\lfloor x*p\rfloor⌊x∗p⌋和x−⌊x∗p⌋x-\lfloor x*p\rfloorx−⌊x∗p⌋的两段,然后其余蚯蚓变长qqq。
求每次切开蚯蚓的长度和最后所以蚯蚓的长度。
解题思路
先不考虑变长
和合并果子的思路很像,我们发现如果从大到小切切出来的也是从大到小的,所以我们开三个队列,第一个队列装初始的蚯蚓,然后切出来的左边装到第二个队列,右边装到第三个队列,这样每个队列的长度也是单调的,之后每次取出三个队头里最长的来剪掉就好了。
考虑变长,初始的蚯蚓第iii次长度为x+i∗qx+i*qx+i∗q,那么我们直接当做所有长度都是x+i∗qx+i*qx+i∗q的蚯蚓,然后将第iii次加入的蚯蚓长度变为x−i∗qx-i*qx−i∗q即可。
时间复杂度O(n+m)O(n+m)O(n+m)
codecodecode
#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);}
}
附上远古时期堆的代码
90ptscode90pts\ code90pts 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);}
}