[AGC034F]RNG and XOR(FWT)

题面

https://atcoder.jp/contests/agc034/tasks/agc034_f

题解

前置知识

首先设得到i的期望步数为E[i]。容易看出E[0]=0以及对i>0,(E[i]=sum_{j=0}^{2^n-1}p[j]E[i igoplus j]+1)

将1移到左边,可以得到(E[i]-1=sum_{j=0}^{2^n-1}p[j]E[i igoplus j])。①

发现这个式子很像一个异或卷积,它可以描述为三个数组之间的关系:

[{{}E[0],E[1],…,E[2^n-1]{}} igoplus {{}p[0],p[1],…,p[2^n-1]{}}={{}?,E[1]-1,E[2]-1,…,E[2^n-1]-1{}} ]

其中(igoplus)表示两个数列之间的异或卷积。?的存在是因为E[0]并不满足①式。不过没关系,我们可以算出?是什么。中间的p数组满足一个性质——它们的和是1。所以,左边所有数的和一定等于右边所有数的和。所以(?=2^n-1)

之后,我们将中间数组的第一项-=1,就可以完美地消掉右边的E:

[{{}E[0],E[1],…,E[2^n-1]{}} igoplus {{}p[0]-1,p[1],…,p[2^n-1]{}}={{}2^n-1,-1,-1,…,-1{}} ]

看上去我们已经做完了,因为中间和右边的数组都已知,求左边还不容易吗?只需要把右边进行FWT,再与中间FWT后的结果的逆元逐项相乘,再UFWT就是左边了。

问题就出在“逆元”上。

0是没有逆元的,而我们仔细思考,发现中间FWT以后,是会出现0的!出现0的就是第一项,这一项在FWT以后会变成(p[0]-1+p[1]+…+p[2^n-1]),也就是0。其他项可以证明不是0。核对右边的第一项,FWT以后变成(2^n-1-1-1…-1)也是0。感觉我们少了个条件,做不下去了。

并不是!其实E中也有一项已知的,就是(E[0]=0)。它可是有巨大的用途的。根据我们的推导,({{}E[0],E[1],…,E[2^n-1]{}})FWT以后的结果是({{}q[0],q[1],…,q[2^n-1]{}}),这个q的1到(2^n-1)都已知了,只有q[0]未知。左边是E[0]已知,其他未知。根据异或卷积的公式,一定存在下列关系

[frac{frac{frac{frac{q[0]+q^{(1)}[2^0]}{2}+q^{(2)}[2^1]}{2}+q^{(3)}[2^2]}{…}+q^{(n)}[2^{n-1}]}{2}=E[0]=0 ]

其中(q^{(i)}[j])表示FWT中进行第i轮循环时,q[j]的值。由于(q^{(1)}[2^0],q^{(2)}[2^1],…,q^{(n)}[2^{n-1}])这些值都与q[0]线性无关,所以简化为

[frac{q[0]}{2^n}+M=0 ]

这个M极其繁琐,怎么求?

强行代q[0]=0,算一个UFWT,算出来(E[0]=k)。这代表了(frac{0}{2^n}+M=k),M自然求出。

至此,q[0]求出,本题结束。总时间复杂度(O(n2^n))

代码

#include<bits/stdc++.h>

using namespace std;

#define ll long long
#define rg register
#define In inline

const int N = 262144;
const ll mod = 998244353;
const ll iv2 = 499122177;

In ll read(){
	ll s = 0,ww = 1;
	char ch = getchar();
	while(ch < '0' || ch > '9'){if(ch == '-')ww = -1;ch = getchar();}
	while('0' <= ch && ch <= '9'){s = 10 * s + ch - '0';ch = getchar();}
	return s * ww;
}

In void write(ll x){
	if(x < 0)putchar('-'),x = -x;
	if(x > 9)write(x / 10);
	putchar('0' + x % 10);
}

namespace ModCalc{
	In void Inc(ll &x,ll y){
		x += y;if(x >= mod)x -= mod;
	}
	In void Dec(ll &x,ll y){
		x -= y;if(x < 0)x += mod;
	}
	In ll Add(ll x,ll y){
		Inc(x,y);return x;
	}
	In ll Sub(ll x,ll y){
		Dec(x,y);return x;
	}
}
using namespace ModCalc;

In ll power(ll a,ll n){
	ll s = 1,x = a;
	while(n){
		if(n & 1)s = s * x % mod;
		x = x * x % mod;
		n >>= 1;
	}
	return s;
}

ll n,deg;
ll p[N+5],q[N+5],temp[N+5];

In void calc(ll &x,ll &y,int opt){
	if(opt == 1){
		ll X = Add(x,y),Y = Sub(x,y);
		x = X,y = Y;
	}
	else{
		ll X = Add(x,y) * iv2 % mod,Y = Sub(x,y) * iv2 % mod; 
		x = X,y = Y;
	}
}

void FWT(ll a[],ll deg,int opt){
	for(rg int n = 2;n <= deg;n <<= 1){
		int m = n >> 1;
		for(rg int i = 0;i < deg;i += n){
			for(rg int j = 0;j < m;j++)calc(a[i+j],a[i+j+m],opt);
		}
	}
}

int main(){
	n = read();
	deg = 1ll << n;
	ll s = 0;
	for(rg int i = 0;i < deg;i++)p[i] = read(),s += p[i];
	ll iv = power(s,mod - 2);
	for(rg int i = 0;i < deg;i++)p[i] = p[i] * iv % mod;
	Dec(p[0],1);
	FWT(p,deg,1);
	for(rg int i = 0;i < deg;i++)q[i] = (i == 0 ? deg - 1 : -1);
	FWT(q,deg,1);
	for(rg int i = 1;i < deg;i++)q[i] = q[i] * power(p[i],mod - 2) % mod;
	memcpy(temp,q,sizeof(temp));
	FWT(temp,deg,-1);
	Dec(q[0],temp[0] * deg % mod);
	FWT(q,deg,-1);
	for(rg int i = 0;i < deg;i++)write(q[i]),putchar('
');
	return 0;
}
原文地址:https://www.cnblogs.com/xh092113/p/12393170.html