简要题意 : (0) 到 (2^n-1) 的数每一个数有一个出现概率(p_i) (保证(sum p_i =1)) ,数x初始是0,每次异或上出现的数,对每个数求x最先变成这个数的期望次数
首先转化问题,考虑我们求的相当于是每个数变成0的期望次数。
于是设(x[i])表示i的答案
[egin {aligned}
x[i] &= sum x[j]*p_{i xor j} + 1 (i>0)
\
x[0] &= 0
end {aligned}
]
写成异或卷积
[lbrace x[0],x[1],x[2],...
brace XOR lbrace p[0],p[1],p[2],...
brace
= lbrace x[0] + {2^n} -1,x[1]-1,x[2]-1,...
brace
]
[lbrace x[0],x[1],x[2],...
brace XOR lbrace p[0]-1,p[1],p[2],...
brace
= lbrace {2^n} -1,-1,-1,...
brace
]
然后异或卷积下做一次求逆就行了。
注意的是0这个位置是{0,0},这个可以用x[0]=0还原。
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=998244353;
inline int add(int a,int b){a+=b;return a>=mod?a-mod:a;}
inline int sub(int a,int b){a-=b;return a<0?a+mod:a;}
inline int mul(int a,int b){return (ll)a*b%mod;}
inline int qpow(int a,int b){int ret=1;for(;b;b>>=1,a=mul(a,a))if(b&1)ret=mul(ret,a);return ret;}
const int inv2=qpow(2,mod-2);
/* math */
int n,s;
inline void FWT(int *t,int n,int type){//xor
for(int step=1;step<n;step<<=1)
for(int i=0;i<n;i+=step<<1)
for(int j=0;j<step;j++){
int x=t[i+j],y=t[i+j+step];
t[i+j]=add(x,y),t[i+j+step]=sub(x,y);
if(type==-1)t[i+j]=mul(t[i+j],inv2),t[i+j+step]=mul(t[i+j+step],inv2);
}
}
const int N=1<<18;
int p[N],a[N];
int main()
{
cin >> n;
for(int i=0;i<1<<n;i++)scanf("%d",&p[i]),s=add(s,p[i]);
s=qpow(s,mod-2);for(int i=0;i<1<<n;i++)p[i]=mul(p[i],s);
for(int i=1;i<1<<n;i++)a[i]=mod-1;a[0]=(1<<n)-1;
p[0]=sub(p[0],1);
FWT(a,1<<n,1),FWT(p,1<<n,1);
for(int i=0;i<1<<n;i++)a[i]=mul(a[i],qpow(p[i],mod-2));
FWT(a,1<<n,-1);
for(int i=0;i<1<<n;i++){
printf("%d
",sub(a[i],a[0]));
}
}