正解
思考的时候没有得到除了高斯消元以外的思路……
原来是一道板子题……
设
p
i
p_i
pi为选
i
i
i的概率,
e
i
e_i
ei为
i
i
i第一次变成
0
0
0的期望步数(显然和
0
0
0第一次变成
i
i
i一样)
显然可以列出式子:
e
i
=
1
+
∑
p
j
e
i
⨁
j
e_i=1+\sum p_je_{i\bigoplus j}
ei=1+∑pjei⨁j
e
0
=
0
e_0=0
e0=0
用集合幂级数来表示
e
e
e和
p
p
p,分别记为
E
E
E和
P
P
P。
乘法定义为异或运算。
于是有
E
+
c
=
I
+
P
∗
E
E+c=I+P*E
E+c=I+P∗E
I
I
I表示全部位置都是
1
1
1的集合幂级数。
c
c
c是用来修正
E
0
E_0
E0的常数。
“集合幂级数”只是个高大上的名词……
类似于多项式,一个集合幂级数表示成这个样子: F = ∑ a i x i F=\sum a_ix^i F=∑aixi
和多项式不同的是,这里按照需要定义了 x a ∗ x b x^a*x^b xa∗xb的结果。比如,如果乘法定义为异或,那么 x a ∗ x b = x a ⨁ b x^a*x^b=x^{a \bigoplus b} xa∗xb=xa⨁b
设
S
(
F
)
S(F)
S(F)表示
∑
F
i
\sum F_i
∑Fi
于是有
S
(
E
)
+
c
=
2
n
+
S
(
P
)
S
(
E
)
S(E)+c=2^n+S(P)S(E)
S(E)+c=2n+S(P)S(E)
S ( P ∗ E ) = S ( P ) S ( E ) S(P*E)=S(P)S(E) S(P∗E)=S(P)S(E)
因为 P P P中每个数和 E E E中每个数都可以做出贡献。
由于
S
(
P
)
=
1
S(P)=1
S(P)=1,所以
c
=
2
n
c=2^n
c=2n
所以
E
+
2
n
=
I
+
P
∗
E
E+2^n=I+P*E
E+2n=I+P∗E
移项得
2
n
−
I
=
(
P
−
1
)
∗
E
2^n-I=(P-1)*E
2n−I=(P−1)∗E
做
F
W
T
FWT
FWT得
F
W
T
(
2
n
−
I
)
=
F
W
T
(
P
−
1
)
F
W
T
(
E
)
FWT(2^n-I)=FWT(P-1)FWT(E)
FWT(2n−I)=FWT(P−1)FWT(E)
考虑计算
F
W
T
(
E
)
i
FWT(E)_i
FWT(E)i。可以只有
i
=
0
i=0
i=0时
F
W
T
(
P
−
1
)
=
0
FWT(P-1)=0
FWT(P−1)=0。
i
>
0
i>0
i>0时就暴力算出,
i
=
0
i=0
i=0时根据
E
0
=
0
E_0=0
E0=0手玩出
F
W
T
(
E
)
0
FWT(E)_0
FWT(E)0的取值。
算出 F W T ( E ) FWT(E) FWT(E)之后 I F W T IFWT IFWT回去即可。
代码
using namespace std;
#include <cstdio>
#include <cstring>
#include <algorithm>
#define N 18
#define ll long long
#define mo 998244353
ll qpow(ll x,int y=mo-2){
ll r=1;
for (;y;y>>=1,x=x*x%mo)
if (y&1)
r=r*x%mo;
return r;
}
int n;
int a[1<<N],p[1<<N],e[1<<N],f[1<<N];
void fwt(int F[]){
for (int i=1;i<1<<n;i<<=1)
for (int j=0;j<1<<n;j+=i<<1)
for (int k=j;k<j+i;++k){
int x=F[k],y=F[k+i];
F[k]=(x+y)%mo;
F[k+i]=(x-y+mo)%mo;
}
}
int main(){
scanf("%d",&n);
ll sum=0;
for (int i=0;i<1<<n;++i)
scanf("%d",&a[i]),sum+=a[i];
sum=qpow(sum);
for (int i=0;i<1<<n;++i)
p[i]=a[i]*sum%mo;
for (int i=0;i<1<<n;++i)
f[i]=-1+mo;
(f[0]+=1<<n)%=mo;
fwt(f);
(p[0]=p[0]-1+mo)%=mo;
fwt(p);
sum=0;
for (int i=1;i<1<<n;++i){
e[i]=(ll)f[i]*qpow(p[i])%mo;
sum+=e[i];
}
e[0]=(mo-sum%mo)%mo;
fwt(e);
ll inv=qpow(1<<n);
for (int i=0;i<1<<n;++i)
e[i]=e[i]*inv%mo;
for (int i=0;i<1<<n;++i)
printf("%d\n",e[i]);
return 0;
}