AGC034 F - RNG and XOR
简要题意 : \(0\) 到 \(2^n-1\) 的数每一个数有一个出现概率\(p_i\) (保证\(\sum p_i =1\)) ,数x初始是0,每次异或上出现的数,对每个数求x最先变成这个数的期望次数
首先转化问题,考虑我们求的相当于是每个数变成0的期望次数。
于是设\(x[i]\)表示i的答案
\[\begin {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],... \rbrace XOR \lbrace p[0],p[1],p[2],... \rbrace
= \lbrace x[0] + {2^n} -1,x[1]-1,x[2]-1,... \rbrace
\]
\[\lbrace x[0],x[1],x[2],... \rbrace XOR \lbrace p[0]-1,p[1],p[2],... \rbrace
= \lbrace {2^n} -1,-1,-1,... \rbrace
\]
然后异或卷积下做一次求逆就行了。
注意的是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\n",sub(a[i],a[0]));
}
}