[ABC409G] Accumulation of Wealth 题解
一道很不错的多项式题。
我们先转化题意:有
那么,如果一直做操作一,我们发现数组会先加入
首先我们要求的是期望
接下来处理
我们要算它第一次出现的概率。那么我们假设操作了
那么假设它已经出现了,这时候后面还有
接下来我们考虑计算
首先如果现在有
不难得出边界条件
接下来,我们只需要将前
我们开始化简。首先我们可以将
然后我们将组合数展开:
然后将与
接着做一个很巧妙的转化:
注意到
那么我们定义多项式
那么
多项式乘法可以用 NTT 或者 FFT,容易做到
这时候,我们不难发现
因此,总复杂度为
代码:
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int N=300010;
const int mod=998244353;
const int G=3;//mod 的原根
const int Gi=332748118;//原根的逆元
int inv[N];
int ijc[N];
int jc[N];
void init(int n){
inv[1]=1;
jc[0]=1;
ijc[0]=1;
for(int i=2;i<=n;i++)inv[i]=(mod-mod/i)*inv[mod%i]%mod;//逆元
for(int i=1;i<=n;i++){
jc[i]=jc[i-1]*i%mod;//阶乘
ijc[i]=ijc[i-1]*inv[i]%mod;//阶乘的逆元
}
return;
}
int C(int n,int m){//可以省略
if(n<m)return 0;
int fz=jc[n];
int fm=ijc[m]*ijc[n-m]%mod;
return fz*fm%mod;
}
int ksm(int a,int b){//快速幂
int z=1;
while(b){
if(b&1)z=z*a%mod;
a=a*a%mod;
b>>=1;
}
return z;
}
int Inv(int x){//O(n log n)求逆元
return ksm(x,mod-2);
}
int a[N],b[N];
int r[N];
void NTT(int len,int *a,int on){//Not Too TLE (NTT 多项式乘法qwq)
for(int i=0;i<len;i++)
if(i<r[i])
swap(a[i],a[r[i]]);
for(int mid=1;mid<len;mid<<=1){
int Wn=ksm(on==1?G:Gi,(mod-1)/(mid*2));
int B=mid<<1;
for(int i=0;i<len;i+=B){
int W=1;
for(int j=0;j<mid;j++,W=(W*Wn)%mod){
int A=a[i+j];
int B=a[i+j+mid];
a[i+j]=((A+W*B)%mod+mod)%mod;
a[i+j+mid]=((A-W*B)%mod+mod)%mod;
}
}
}
if(on==1)return;
int _inv=Inv(len);
for(int i=0;i<=len;i++)a[i]=(a[i]*_inv)%mod;
return;
}
int n,m,p;
int f[N];
int E[N];
int _=1,l;
void solve(){//做多项式乘法
_=1;l=0;
while(_<=m+m){
_<<=1;
l++;
}
for(int i=0;i<_;i++)r[i]=(r[i>>1]>>1)|((i&1)<<l-1);
NTT(_,a,1);
NTT(_,b,1);
for(int i=0;i<=_;i++)a[i]=a[i]*b[i]%mod;
NTT(_,a,-1);
return;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
init(N-10);
cin>>n>>p;
m=n-2;//多项式上界
p=p*inv[100]%mod;//p=p/100
f[0]=1;
for(int i=1;i<=n;i++)f[i]=f[i-1]*(n-i+1-p)%mod*inv[n-i]%mod;//预处理f(i)
for(int i=0;i<=m;i++)a[i]=ksm((1-p+mod)%mod,i)*ijc[i]%mod;//填充多项式 F
for(int i=0;i<=m;i++)b[i]=f[i]*jc[n-i-2]%mod;//填充多项式 G
solve();//多项式乘法
for(int i=2;i<=n;i++)E[i]=ksm(p,i-1)*ijc[i-2]%mod*a[n-i]%mod;//求期望
int ss=0;
for(int i=2;i<=n;i++)ss=(ss+E[i])%mod;//求sum_{k=2}^{n}E_i
E[1]=(n-ss)%mod;//求 E_1
for(int i=1;i<=n;i++)E[i]=(E[i]%mod+mod)%mod;
for(int i=1;i<=n;i++)cout<<E[i]<<"\n";
return 0;
}
/*
*/
确实很不错。