[AGC034F] RNG and XOR

一、题目

点此看题

二、解法

\(f(i)\) 表示第一次走到 \(i\) 的期望操作次数,初始化 \(f(0)=0\),对于 \(i\in[1,2^n)\),转移枚举从 \(0\) 开始的第一步:

\[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)=\frac{\vec g(i)+\vec z(i)}{1-\vec p(i)}\)

但是我们还不知道 \(\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);
}
posted @ 2022-06-25 21:01  C202044zxy  阅读(67)  评论(0编辑  收藏  举报