约定下文中:
- P,F,G,H 均表示集合幂级数。
- P 集合是每一项是概率。
- 集合幂级数乘法是异或卷积。
- S1⊕S2 表示集合对称差,也就是异或。
如果 P∅′=0 会有自己转移到自己的情况,为了方便,钦定:
PS={01−P∅′PS′S=∅S=∅
每一步选到非空的期望是 1−P∅′1,所以答案乘上这个值即可。
设 FS 表示走到 S 状态期望步数,列出转移:
FS={01+∑TFS⊕TPTS=∅S=∅
观察转移中这个求和,考虑把求和消掉,考虑进行一个变换,设:
GS={−1PSS=∅S=∅
设 H=F∗G,当 S=∅,F∅=∑SFSPS,又观察到:
S∑FSS∑FSS∑FSS∑FSPS=S=∅∑(1+T∑FS⊕TPT)=2n−1+S∑FST=S∑PT=2n−1+S∑FS(1−PS)=2n−1
当 S=∅:
FS=−FS+T∑FS⊕TPT=−1
整理得:
HS={2n−1−1S=∅S=∅
进行 FWT 变换,可以求得 G~,H~,但由于 H~∅=∑HS=0,所以无法直接求得 F~∅,但是观察 FWT 过程发现 2nF∅=∑H~S=0,所以可以算出 F~∅,逆最后变换就行。
int i,j,l;
int n=read();
int maxs=1<<n;
mint sum=0,p0;
for(i=0;i<maxs;++i) sum+=(f[i]=read());
for(sum=sum.inverse(),i=0;i<maxs;++i) f[i]*=sum;
f[0]-=1;
for(l=1;l<maxs;l*=2) for(i=0;i<maxs;i+=l*2) for(j=0;j<l;++j)
f[i+j]+=f[i+j+l],f[i+j+l]=f[i+j]-f[i+j+l]-f[i+j+l];
for(i=1;i<maxs;++i) f[i]=mint(maxs)/f[i],f[0]-=f[i];
for(l=1;l<maxs;l*=2) for(i=0;i<maxs;i+=l*2) for(j=0;j<l;++j)
f[i+j]+=f[i+j+l],f[i+j+l]=f[i+j]-f[i+j+l]-f[i+j+l],f[i+j]/=2,f[i+j+l]/=2;
for(i=0;i<maxs;++i) print(f[i].get()),putchar('\n');
其实这个题形式和 P5326 [ZJOI2019] 开关差不多,而题解 P5326 【[ZJOI2019]开关】 - 洛谷专栏提供的异或卷积做法十分易懂,同样也能用于此题。
本文同步自洛谷专栏,保留原始正文与发布时间。在洛谷查看原文 ↗