[ 2019牛客暑期多校训练营(第一场) ] D Parity of Tuples

题目大意:有n个m元组v1,v2,,vn,第i个m元组vi=ai,1,ai,2,,ai,m。定义count(x)为这n个m元组中,对所有j=1m满足ai,jx的二进制表示中有奇数个1的m元组的个数。求count(x),x=02k1,其中1n1050ai,j<2k1k201m10

题解:观察FWHT中的Haramard矩阵,Hij=(1)count1(i and j),其中count1(x)表示x的二进制表示中1的数量;这和我们题目中要的东西很像。关于这道题目,我们可以发现我们并不需要做什么卷积;也就是说,我们其实并没有在做一个完整的FWHT。做这道题主要用到的是FWHT中的那个Haramard变换矩阵,然后我们有方法在和这个矩阵做矩阵乘法的时候把时间复杂度降到O(nlog(n)),所以做这道题只需要知道Hij=(1)count1(i and j),然后贴个FWHT的板子使做该矩阵乘法的时间复杂度降到O(nlog(n))就好了(完全不知道WHT是啥的也可以先看一下http://www.zarxdy34.top/?p=203来帮我增加一下访问量)。

为了方便起见,设f(x)=(1)count1(x),即x二进制表示下有奇数个1时为-1,偶数个1时为1,Hij=f(ij)。由于有如下性质:

Ht(xy)=(1)count1(t and(xy))=(1)count1((t and x)(t and y))2k=(1)count1((t and x)(t and y))=HtxHty

所以有f(xy)=f(x)f(y)

设向量X=(X0,X1,,X2k1),考虑Y=HX,有

Yi=j=02k1HijXj

即如果f(ij)=1,则向量XYi的贡献加上Xj,否则减去Xj

现在固定x=t,考虑每一个m元组的生成函数Fi,我们想要让[xt]WHT(Fi)=1(也就是HFi所得向量的第t项)当且仅当对所有j=1mf(ai,ju)=1,即如果有一个count1(ai,ju)为偶数则贡献为0。要让该式子对[xt]WHT(Fi) 贡献为1很难做到(其实也不难,就是下面那个东西除以2m),但是我们只要做到让它的贡献为与ai,j无关的一个定值就可以了。设bj=f(ai,ju),构造式子

(1+b1)(1+b2)(1+b3)(1+bm)

只要其中出现了一次bj=1,即某个ai,ju中1的个数为偶数时,该式的值即为0;否则,该式值恒为2m

对于式子中的bj,我们对该式的生成函数Fi+=(1)xaj,对应位置上就加上了bj的贡献。但式子展开后还有一个常数项以及若干个bjk的乘积,至于bj1bj2之类的项,由于有如下性质:

所以可以发现,bj1bj2对应的项是xai,j1ai,j2,系数就是它们的乘积,(单个为-1,所以两个异或起来的就是1,三个则是-1,依次类推),常数项对应一个都不取的情况。

由于FWHT是一个线性运算,所以可以把每个m元组,甚至每个m元组中的每一项的贡献单独计算并相加,所以就可以直接先把所有项全部加起来然后直接做一次FWHT得出答案。

#include <bits/stdc++.h>
using namespace std;
const int maxn=1<<20,mo=1e9+7;
void FWHT(int *arr,int N,int inv_flg=0)
{
	for (int k=1;k<N;k<<=1)
	for (int i=0;i<N;i+=(k<<1))
	for (int j=0;j<k;j++)
	{
		if (inv_flg)
		{
			int x=arr[i+j],y=arr[i+j+k];
			arr[i+j]=(x+y)/2;
			arr[i+j+k]=(x-y)/2;
		}
		else
		{
			int x=arr[i+j],y=arr[i+j+k];
			arr[i+j]=x+y;
			arr[i+j+k]=x-y;
		}
	}
}
int f[maxn];
int a[11];
int n,m,k,N;
void DFS(int x,int res,int p)
{
	if (x==m)
	{
		f[res]+=p;
		return;
	}
	DFS(x+1,res,p);
	DFS(x+1,res^a[x],-p);
}
int main()
{
	while (scanf("%d%d%d",&n,&m,&k)!=EOF)
	{
		for (int i=0;i<(1<<k);i++) f[i]=0;
		for (int i=0;i<n;i++)
		{
			for (int j=0;j<m;j++) scanf("%d",&a[j]);
			DFS(0,0,1);
		}
		FWHT(f,1<<k);
		int res=0;
		for (int i=0,p=1;i<(1<<k);i++,p=p*3ll%mo)
			res^=(long long)p*(f[i]>>m)%mo;
		printf("%d\n",res);
	}
}

Leave a Reply

Your email address will not be published.