UOJ#310 【UNR #2】黎明前的巧克力 FWT 多项式

原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ310.html

题目传送门 - UOJ#310

题意

  给定 $n$ 个数 ,请你选出两个不相交的集合(两个集合交换一下也算一种),问有多少种选择方案使得两个集合各自包含的数的异或值 相等。

  不能两个都不选。

  $n,a_i\leq 10^6$

题解

  首先,问题可以转化成:选择两个集合,他们的异或值为 $0$ 。

  我们可以构造幂级数。

  对于 $a_i$ 我们构造: $h_i(x)=x^0+2x^{a_i}$ 。

  表示的意义是不选 $a_i$ 有一种方案,选择 $a_i$ 可以把它随便扔给两个集合,有两种方案。

  于是我们只需要把所有的这些幂级数做一个异或卷积就可以了。这里注意一下我们可以通过把每一个多项式的 FWT 乘起来得到最终式子的 FWT 。

  但是直接 FWT 显然要 TLE 。

  我们考虑观察一下这个东西的特殊性质。

  对于同一个多项式 $f$ ,我们观察到 $f_i$ 只有两个系数不为 $0$ 的:$f_0=1,f_{a_i}=2$

  考虑 FWT 的变换式(注意一下这里的 $f_0$ 和 $f_1$ 的意义略有不同,这里是分别指 $f$ 的左边一半和右边一半):

$$FWT(f)=(FWT(f_0-f_1),FWT(f_0+f_1))$$

  仔细分析可以发现:$f_0$ 对于任意 $FWT(f)_i$ 的贡献都为 $1$ 。而 $f_{a_i}$ 对任意 $FWT(f)_i$ 的贡献只有 $\pm 2$ 两种。

  于是 $FWT(f)_i=-1$ 或 $FWT(f)_i=3$ 。

  得到这个结论可以干什么?我们仍然不能把它暴力乘起来。

  但是我们如果得到了所有式子的 FWT 之和,是不是就可以得到 $-1$ 和 $3$ 的个数了?

  对于 FWT ,我们有 $FWT(f+g)=FWT(f)+FWT(g)$ ,即所有多项式的和的 FWT 等于 所有的多项式的 FWT 之和。

  于是我们可以一次 FWT 得到 对于每一个下标的 ,所有多项式的 FWT 的该下标的值的和。

  于是我们可以对于每一个下标,解出这个下标的 $-1$ 的个数,设为 $x$ ,那么,我们就可以得到我们一开始需要的:乘积 $=(-1)^x3^{n-x}$ 。

  然后再 IFWT 回来。

  由于要除掉都不选的情况,$f_0-1$ 就是答案。

代码

#include <bits/stdc++.h>
using namespace std;
const int N=1<<20,mod=998244353;
const int inv2=499122177,inv4=748683265;
int n,m=1<<20,a[N],Pow3[N];
void FWT(int a[],int n,int flag){
	for (int d=1;d<n;d<<=1)
		for (int i=0;i<n;i+=(d<<1))
			for (int j=0;j<d;j++){
				int x=a[i+j],y=a[i+j+d];
				a[i+j]=(x+y)%mod;
				a[i+j+d]=(x-y+mod)%mod;
				if (flag==-1){
					a[i+j]=1LL*a[i+j]*inv2%mod;
					a[i+j+d]=1LL*a[i+j+d]*inv2%mod;
				}
			}
}
int main(){
	scanf("%d",&n);
	memset(a,0,sizeof a);
	for (int i=1,x;i<=n;i++){
		scanf("%d",&x);
		a[x]+=2,a[0]++;
	}
	FWT(a,m,1);
	Pow3[0]=1;
	for (int i=1;i<m;i++)
		Pow3[i]=1LL*Pow3[i-1]*3%mod;
	for (int i=0;i<m;i++){
		int x=(1LL*(3*n-a[i])*inv4%mod+mod)%mod;
		if (x&1)
			a[i]=(-Pow3[n-x]+mod)%mod;
		else
			a[i]=Pow3[n-x];
	}
	FWT(a,m,-1);
	printf("%d",(a[0]+mod-1)%mod);
	return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/zhouzhendong/p/UOJ310.html