設 ei 表示從 0 走到 i 的期望次數,顯然等於 i 走到 0 的期望次數。
ei={0,1+∑j=02n−1ei⊕j∗pj,i=0i=0
設 E,P 分別爲 ei,pi 的集合冪級數,用異或卷積定義乘法,則有:
E∗P+I=E+c
其中 c 爲一個常數,用於修正 e0。
得到 FWT(E)∗FWT(P)+FWT(I)=FWT(E)+FWT(c)
在 i 處的關係式爲:FWT(E)i∗(FWT(P)i−1)=FWT(c)i−FWT(I)i
其中 FWT(I)=2n,FWT(c)=∑i=02n−1cxi
當 i=0 時,FWT(P)0=∑pi=1,所以 c=FWT(I)0=2n
對於 i>1,FWT(P)i<S(P)=1,所以 FWT(E)i=FWT(P)i−12n
而 FWT(E)0 利用 e0=0=2n1∑j=02n−1FWT(E)j 求解。
實際上可以假設 FWT(E)0=0 求出一個答案 E′,然後實際上 Ei=Ei′+2n1FWT(E)0,所以 2n1FWT(E)0=0−E0′
求出 FWT(E) 後再變換回來就可以了。
雙倍經驗:ZJOI2019開關,題解裏面最後 FWT(G)T=∑i∈/Tpi−∑i∈Tpi 是因爲概率只在單點處有值。
Code:
#include<bits/stdc++.h>
#define maxn 300005
using namespace std;
const int mod = 998244353;
int n,N,p[maxn],E[maxn];
int Pow(int a,int b){int s=1;for(;b;b>>=1,a=1ll*a*a%mod) b&1&&(s=1ll*s*a%mod); return s;}
int upd(int x){return x+(x>>31&mod);}
void FWT(int *a,int len,int flg){
for(int i=2,l=1,v;i<=len;l=i,i<<=1)
for(int j=0;j<len;j+=i)
for(int k=j;k<j+l;k++)
v=a[k],a[k]=upd(v+a[k+l]-mod),a[k+l]=upd(v-a[k+l]);
if(flg^1) for(int i=0,Inv=Pow(len,mod-2);i<len;i++) a[i]=1ll*a[i]*Inv%mod;
}
int main()
{
scanf("%d",&n),N=1<<n; int s=0;
for(int i=0;i<N;i++) scanf("%d",&p[i]),s=upd(s+p[i]-mod);
s=Pow(s,mod-2);
for(int i=0;i<N;i++) p[i]=1ll*p[i]*s%mod;
FWT(p,N,1);
for(int i=1;i<N;i++) E[i]=1ll*N*Pow(upd(p[i]-1),mod-2)%mod;
FWT(E,N,-1);
int x=mod-E[0];
for(int i=0;i<N;i++) printf("%d\n",upd(E[i]+x-mod));
}