一、题目
二、解法
设 \(f(i)\) 表示第一次走到 \(i\) 的期望操作次数,初始化 \(f(0)=0\),对于 \(i\in[1,2^n)\),转移:
\[f(i)=1+\sum_{j=0}^{2^n-1} p(j)\cdot f(i\oplus j)
\]
由于转移有环,我们不妨写成集合幂级数的形式,对转移方程两边同时做异或卷积正变换:
\[\vec f(i)=\vec g(i)+\vec p(i)\cdot \vec f(i)+\vec z(i)
\]
其中 \(g(i)=1\),代表转移方程中的常数项;\(z(0)\) 有值,\(\forall i>0,z(i)=0\),它用来强制 \(f(0)=0\)
考虑 \(i=0\) 时,由于 \(\vec p(0)=1\),可以解出 \(\vec z(i)=-\vec g(0)\),即 \(z(0)=-\vec g(0)\)
考虑 \(i>0\) 时,由于 \(\vec p(0)\not=0\),可以直接解出 \(\vec f(i)=0\)
但是我们还不知道 \(\vec f(0)\) 是多少,由于 \(f(0)=\frac{1}{2^n}\sum_{i=0}^{2^n-1} \vec f(i)=0\),所以 \(\vec f(0)=-\sum_{i=1}^{2^n-1} \vec f(i)\),这样我们可以得到 \(\vec f\) 的每一项,把它逆变换就可以得到 \(f\),即我们的答案。
总之这题是比较套路和明显的,时间复杂度 \(O(n2^n)\)
#include <cstdio>
const int M = (1<<18)+5;
const int MOD = 998244353;
const int inv2 = (MOD+1)/2;
#define int long long
int read()
{
int x=0,f=1;char c;
while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
return x*f;
}
int n,m,p[M],x[M],y[M];
int qkpow(int a,int b)
{
int r=1;
while(b>0)
{
if(b&1) r=r*a%MOD;
a=a*a%MOD;
b>>=1;
}
return r;
}
void fwt(int *a,int n,int op)
{
for(int i=1;i<n;i<<=1)
for(int j=0;j<n;j+=i<<1)
for(int k=0;k<i;k++)
{
int fe=a[j+k],fo=a[i+j+k];
a[j+k]=(fe+fo)%MOD;
a[i+j+k]=(fe-fo+MOD)%MOD;
if(op==-1)
a[j+k]=a[j+k]*inv2%MOD,
a[i+j+k]=a[i+j+k]*inv2%MOD;
}
}
signed main()
{
n=1<<read();
for(int i=0;i<n;i++)
m+=p[i]=read(),y[i]=1;
m=qkpow(m,MOD-2)%MOD;
for(int i=0;i<n;i++)
p[i]=p[i]*m%MOD;
fwt(p,n,1);fwt(y,n,1);
int z=MOD-y[0];
for(int i=1;i<n;i++)
{
x[i]=(y[i]+z)*qkpow(MOD+1-p[i],MOD-2)%MOD;
x[0]=(x[0]+MOD-x[i])%MOD;
}
fwt(x,n,-1);
for(int i=0;i<n;i++)
printf("%lld\n",(x[i]+MOD)%MOD);
}