【XSY3241】暴风士兵(stormtrooper)(多项式分治,期望)

设一个人被扣了 \(i\) 滴血的概率为 \(p_i\),设 \(c_i=exp-i\) 且只有 \(c_0,c_1,\cdots,c_{exp}\) 有值,那么题目就是在问 \(\sum\limits_{i=0}^{exp}c_ip_i\)

我们设 \(p_i\) 的生成函数为 \(P(x)\),那么第 \(i\) 次操作相当于将 \(P(x)\) 乘上 \((p_ix+(1-p_i))\)

那么题目第 \(t\) 次询问要求的即为 \(\sum\limits_{i=0}^{exp}c_i[x^i]P(x)\),其中 \(P(x)=\prod\limits_{i=1}^t(p_ix+(1-p_i))\)

每次求出 \(P(x)\) 并暴力统计答案显然是不现实的。

\(P(x)=A(x)B(x)\)\(A(x)=\prod\limits_{i=1}^k(p_ix+(1-p_i))=\sum\limits_{i=0}^ka_ix^i\)\(B(x)=\prod\limits_{i=k+1}^{t}(p_ix+(1-p_i))=\sum\limits_{i=0}^{t-k}b_ix^i\)

那么:

\[\begin{aligned} ans_t&=\sum\limits_{i=0}^{exp}c_i[x^i]P(x)\\ &=\sum_{i=0}^{exp}c_i[x^i]A(x)B(x)\\ &=\sum_{i=0}^{exp}c_i\sum_{j=0}^ia_jb_{i-j}\\ &=\sum_{i=0}^{exp}b_i\sum_{j=0}^{exp-i}c_{j+i}a_j\\ &=\sum_{i=0}^{exp}c_i'[x^i]B(x) \end{aligned} \]

(其中 \(c_i'=\sum\limits_{j=0}^{exp-i}c_{j+i}a_j\)

然后就可以分治了:假设当前区间为 \([l,r]\),长度为 \(m=r-l+1\),我们可以先递归 \([l,mid]\),算出这段区间的答案,并算出次数为 \(\dfrac{m}{2}\)\(A(x)\),再用它和 \(c_i\) 做减法卷积 \(O(m\log m)\) 算出 \(c_i'\) 的前 \(\dfrac{m}{2}\) 项,然后再把 \(c_i'\) 代入作为新的 \(c_i\) 递归 \([mid+1,r]\),算出这段区间的答案,并算出次数为 \(\dfrac{m}{2}\)\(B(x)\),最后 \(O(m\log m)\) 计算出 \(P(x)=A(x)B(x)\)

总时间复杂度 \(O(n\log^2n)\)

#include<bits/stdc++.h>

#define LN 19
#define N 100010

using namespace std;

namespace modular
{
	const int mod=998244353;
	inline int add(int x,int y){return x+y>=mod?x+y-mod:x+y;}
	inline int dec(int x,int y){return x-y<0?x-y+mod:x-y;}
	inline int mul(int x,int y){return 1ll*x*y%mod;}
}using namespace modular;

inline int poww(int a,int b)
{
	int ans=1;
	while(b)
	{
		if(b&1) ans=mul(ans,a);
		a=mul(a,a);
		b>>=1;
	}
	return ans;
}

inline int read()
{
	int x=0,f=1;
	char ch=getchar();
	while(ch<'0'||ch>'9')
	{
		if(ch=='-') f=-1;
		ch=getchar();
	}
	while(ch>='0'&&ch<='9')
	{
		x=(x<<1)+(x<<3)+(ch^'0');
		ch=getchar();
	}
	return x*f;
}

typedef vector<int> poly;

int lans,n;
int rev[N<<2],w[LN][N<<2][2];
int A[N<<2],B[N<<2];
poly p[N<<2],c[N<<2];

void init(int limit)
{
	for(int bit=0,mid=1;mid<limit;bit++,mid<<=1)
	{
		int len=mid<<1;
		int gn=poww(3,(mod-1)/len);
		int ign=poww(gn,mod-2);
		int g=1,ig=1;
		for(int j=0;j<mid;g=mul(g,gn),ig=mul(ig,ign),j++)
			w[bit][j][0]=g,w[bit][j][1]=ig;
	}
}

void NTT(int *a,int limit,int opt)
{
	opt=(opt<0);
	for(int i=0;i<limit;i++)
		rev[i]=(rev[i>>1]>>1)|((i&1)*(limit>>1));
	for(int i=0;i<limit;i++)
		if(i<rev[i]) swap(a[i],a[rev[i]]);
	for(int bit=0,mid=1;mid<limit;bit++,mid<<=1)
	{
		for(int i=0,len=mid<<1;i<limit;i+=len)
		{
			for(int j=0;j<mid;j++)
			{
				int x=a[i+j],y=mul(w[bit][j][opt],a[i+mid+j]);
				a[i+j]=add(x,y),a[i+mid+j]=dec(x,y);
			}
		}
	}
	if(opt)
	{
		int tmp=poww(limit,mod-2);
		for(int i=0;i<limit;i++)
			a[i]=mul(a[i],tmp);
	}
}

void solve(int k,int l,int r)
{
	if(l==r)
	{
		int pi=read();
		pi=add(pi,lans);
		p[k].push_back(dec(1,pi));
		p[k].push_back(pi);
		printf("%d\n",lans=(add(mul(p[k][0],c[k][0]),mul(p[k][1],c[k][1]))));
		return;
	}
	int mid=(l+r)>>1,lc=k<<1,rc=k<<1|1;
	int len=r-l+1,lenl=mid-l+1,lenr=r-mid;
	for(int i=0;i<=lenl;i++) c[lc].push_back(c[k][i]);
	solve(lc,l,mid);
	int limit=1;
	while(limit<=len+lenl) limit<<=1;
	for(int i=0;i<=len;i++) A[i]=c[k][i];
	for(int i=0;i<=lenl;i++) B[i]=p[lc][lenl-i];
	NTT(A,limit,1),NTT(B,limit,1);
	for(int i=0;i<limit;i++) A[i]=mul(A[i],B[i]);
	NTT(A,limit,-1);
	for(int i=0;i<=lenr;i++) c[rc].push_back(A[lenl+i]);
	for(int i=0;i<limit;i++) A[i]=B[i]=0;
	solve(rc,mid+1,r);
	limit=1;
	while(limit<=len) limit<<=1;
	for(int i=0;i<=lenl;i++) A[i]=p[lc][i];
	for(int i=0;i<=lenr;i++) B[i]=p[rc][i];
	NTT(A,limit,1),NTT(B,limit,1);
	for(int i=0;i<limit;i++) A[i]=mul(A[i],B[i]);
	NTT(A,limit,-1);
	for(int i=0;i<=len;i++) p[k].push_back(A[i]);
	for(int i=0;i<limit;i++) A[i]=B[i]=0;
}

int main()
{
	lans=read(),n=read();
	int limit=1;
	while(limit<=(n<<1)) limit<<=1;
	init(limit);
	for(int i=0;i<=lans;i++) c[1].push_back(lans-i);
	for(int i=lans+1;i<=n;i++) c[1].push_back(0);
	solve(1,1,n);
	return 0;
}
/*
1 1
0
*/
/*
918 991
456307063
488721210
886185325
243931909
217329246
856712605
*/
/*
98908 99965
775551600
543754136
259120750
821986384
362863140
*/
posted @ 2022-10-30 11:01  ez_lcw  阅读(37)  评论(0编辑  收藏  举报