AGC034F题解

题意简述

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

(nle 18)

算法分析

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

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

[E(0)=0 ]

[E(i)=1+sum_{j mathrm{xor} k=i}a_jcdot E(k) , i eq 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_jcdot E(k) , i eq 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
",(e[i]-e[0]+mod)%mod);//调整
	return 0;
}
原文地址:https://www.cnblogs.com/ZigZagKmp/p/14383479.html