NOIP2023模拟8联测29 差后队列

题目大意

定义差后序列为一个数据结构,支持两种操作:

  • 0 x:插入一个数 x x x
  • 1:随机删除一个不是最大值的数,如果只有一个数则删除该数

n n n次操作。

对于每次插入,求这个数期望被删除的时间(如果到最后也没被删除则删除时间为 0 0 0);对于每次删除,求删除的数的期望值。

输出答案对 998244353 998244353 998244353取模后的值。

1 ≤ n ≤ 1 0 6 , 0 < x < 998244353 1\leq n\leq 10^6,01n106,0<x<998244353


题解

首先,我们发现,不是最大值的数是等价的。

会有删空的情况,那我们就对每一段单独处理。

我们先考虑每次插入时的询问。设 n w i nw_i nwi表示在第 i − 1 i-1 i1次操作后的不是最大值的数的期望被删除的时间,设第 i − 1 i-1 i1次操作后当前队列中不是最大值的数有 k k k个,则

n w i = 1 k + k − 1 k × n w i − 1 nw_i=\dfrac 1k+\dfrac{k-1}{k}\times nw_{i-1} nwi=k1+kk1×nwi1

对于每个插入的数,找到后面第一个比它大的数的插入时间 t t t,则 n w t nw_t nwt即为当前插入操作的答案。

再考虑删除操作。我们设 s u m sum sum表示当前队列中不是最大值的数的期望和,设 m x mx mx为当前的最大值。对于每次插入,判断当前插入的数 k k k是否大于 m x mx mx。如果大于 m x mx mx,则将原来的最大值加到 s u m sum sum中,并将 k k k设为新的最大值;否则将 k k k加到 s u m sum sum中。对于每次删除,删除的数的期望值为 s u m k \frac{sum}{k} ksum,删除后队列中不是最大值的数的期望和为 k − 1 k ⋅ s u m \frac{k-1}{k}\cdot sum kk1sum,令 s u m = k − 1 k ⋅ s u m sum=\frac{k-1}{k}\cdot sum sum=kk1sum即可。

时间复杂度为 O ( n ) O(n) O(n)

code

#include
using namespace std;
const int N=1000000;
const long long mod=998244353;
int n,mx,hv[N+5],nxt[N+5],ed[N+5];
long long sum=0,jc[N+5],ny[N+5],nw[N+5],ans[N+5];
struct node{
	int tp,x;
}w[N+5];
long long mi(long long t,long long v){
	if(!v) return 1;
	long long re=mi(t,v/2);
	re=re*re%mod;
	if(v&1) re=re*t%mod;
	return re;
}
void init(){
	jc[0]=1;
	for(int i=1;i<=N;i++) jc[i]=jc[i-1]*i%mod;
	ny[N]=mi(jc[N],mod-2);
	for(int i=N-1;i>=0;i--) ny[i]=ny[i+1]*(i+1)%mod;
}
int main()
{
	freopen("queue.in","r",stdin);
	freopen("queue.out","w",stdout);
	init();
	scanf("%d",&n);
	for(int i=1;i<=n;i++){
		hv[i]=hv[i-1];
		scanf("%d",&w[i].tp);
		if(w[i].tp==0){
			scanf("%d",&w[i].x);
			++hv[i];
			if(w[i].x>w[mx].x){
				nxt[mx]=i;mx=i;
			}
			else nxt[i]=i;
		}
		else{
			--hv[i];
			if(!hv[i]){
				ed[mx]=i;
				nxt[mx]=i;mx=0;
			}
		}
	}
	for(int i=n;i>=1;i--){
		if(w[i].tp==0){
			nw[i]=nw[i+1];
			if(w[nxt[i]].tp!=1) ed[i]=nw[nxt[i]];
		}
		else{
			if(!hv[i]) nw[i]=0;
			else{
				long long nyt=ny[hv[i]]*jc[hv[i]-1]%mod;
				nw[i]=(1ll*i*nyt%mod+nyt*(hv[i]-1)%mod*nw[i+1]%mod)%mod;
			}
		}
	}
	mx=0;
	for(int i=1;i<=n;i++){
		if(w[i].tp==0){
			if(w[i].x>w[mx].x){
				sum=(sum+w[mx].x)%mod;mx=i;
			}
			else sum=(sum+w[i].x)%mod;
		}
		else{
			if(!hv[i]){
				ans[i]=w[mx].x;
				sum=0;mx=0;
			}
			else{
				long long nyt=ny[hv[i]]*jc[hv[i]-1]%mod;
				ans[i]=sum*nyt%mod;
				sum=nyt*(hv[i]-1)%mod*sum%mod;
			}
		}
	}
	for(int i=1;i<=n;i++){
		if(w[i].tp==0) printf("%d ",ed[i]);
		else printf("%lld ",ans[i]);
	}
	return 0;
}

你可能感兴趣的:(题解,题解,c++)