ZigZagKmp
Think twice, code once.

题意简述

给定 \(n\)\(2^n\) 个数,初始有一个数\(x=0\),每次操作有一定概率选中 \(i\) ,并将 \(x\) 变成 \(x\ \mathrm{xor}\ i\) ,问将 \(x\) 第一次变为某个数的期望操作次数。

\(n\le 18\)

算法分析

\(E(i)\) 表示 \(x\) 第一次从 \(0\) 变为 \(i\) 的期望步数。

不难得到如下 \(2^n\) 个方程:

\[E(0)=0 \]

\[E(i)=1+\sum_{j \ \mathrm{xor}\ k=i}a_j\cdot E(k)\ ,\ i\neq 0 \]

这个形式是比较标准的 FWT 形式,考虑把 \(E(i)\) 写成生成函数:

\[E=I+E*A \]

(注:此处的乘号表示的是广义乘法,本题中对应 xor 卷积)

但这个式子对常数项等细节处理并不正确,当我们把两边的所有系数相加,会发现 \(0=2^n\)

因此实际上是这样的:

\[E+2^n=I+E*A \]

\[E=\frac{I-2^n}{1-A} \]

这样在 FWT 后点值可以直接相除,即可解决。

最后还有一个问题,把上面求出的 \(E\) 进行 IFWT 后会发现可能不满足 \(E(0)=0\) ,考虑回到最原始的式子:

\[E(i)=1+\sum_{j \ \mathrm{xor}\ k=i}a_j\cdot E(k)\ ,\ i\neq 0 \]

因为 \(\sum a_i=0\) ,所以对所有 \(E(i)\) 同时加上一个常数 \(t\) 不影响正确性,即可调整。

时间复杂度 \(O(n2^n)\)

代码实现

#include<bits/stdc++.h>
using namespace std;
#define maxn 1000005
#define maxm 2000005
#define inf 0x3f3f3f3f
#define int long long
#define mod 998244353
#define local
void file(string s){freopen((s+".in").c_str(),"r",stdin);freopen((s+".out").c_str(),"w",stdout);}
template <typename Tp> void read(Tp &x){
	int fh=1;char c=getchar();x=0;
	while(c>'9'||c<'0'){if(c=='-'){fh=-1;}c=getchar();}
	while(c>='0'&&c<='9'){x=(x<<1)+(x<<3)+(c&15);c=getchar();}x*=fh;
}
int ksm(int b,int p,int Mod=mod){int ret=1;while(p){if(p&1)ret=1ll*ret*b%Mod;b=1ll*b*b%Mod;p>>=1;}return ret;}
int n,m;
int a[maxn],b[maxn],e[maxn];
void fwt(int *f,int typ){
	for(int len=1;len<n;len<<=1){
		for(int i=0;i<n;i+=(len<<1)){
			for(int j=0;j<len;++j){
				int l=f[i+j],r=f[i+j+len];
				f[i+j]=(l+r)%mod;
				f[i+j+len]=(l-r+mod)%mod;
			}
		}
	}
	if(typ==-1){
		int NN=ksm(n,mod-2);
		for(int i=0;i<n;++i)f[i]=1ll*f[i]*NN%mod;
	}
}
signed main(){
	int sm=0;
	read(n);n=(1<<n);
	for(int i=0;i<n;++i)read(a[i]),sm=(sm+a[i])%mod;
	sm=ksm(sm,mod-2);
	for(int i=0;i<n;++i)a[i]=1ll*a[i]*sm%mod;
	a[0]=(a[0]-1+mod)%mod;//处理出 1-A
	for(int i=0;i<n;++i)b[i]=(mod-1);
	b[0]=(b[0]+n+mod)%mod;//处理出 I-2^n
	fwt(a,1);fwt(b,1);
	for(int i=0;i<n;++i)e[i]=1ll*b[i]*ksm(a[i],mod-2)%mod;//直接点值相除
	fwt(e,-1);
	for(int i=0;i<n;++i)printf("%lld\n",(e[i]-e[0]+mod)%mod);//调整
	return 0;
}
posted on 2021-02-06 23:06  ZigZagKmp  阅读(96)  评论(0编辑  收藏  举报