• 6467. 【GDOI2020模拟02.09】西行寺无余涅槃(FWT的性质)


    题目描述

    题解

    吼题

    推荐博客:https://www.cnblogs.com/jz-597/p/12300760.html

    最暴力的做法是把n个2^m的FWT乘起来,这样显然不行

    先把pi,1~k异或上pi,1,把pi,1变为0,最后再把pi,1异或回去

    考虑FWT(xor)的本质,tr(A)=(tr(A1)+tr(A2),tr(A1)-tr(A2)),倒着做可以发现只有变换的u和u+2^k(u&2^k=0)只有u+2^k--->u+2^k这一操作时才需要变号

    要求FWT(A)i,就等于把j=0~N-1(N表示FWT的大小,注意大小写)通过不断变号最后加到位置i,变换的实质是把j从后往前一位位变成i

    根据上面的结论,只有i和j在当前位都为1时才会变号

    记|x|表示x中1的位数,所以(FWT(A)_i=∑_{j=0}^{N-1}{(-1)^{|i&j|}A_j})


    n个FWT的每一位只有2^(k-1)种取值(a1必然为正,x&0=0),因此第(I)(注意大小写)位的乘积可以表示成(prod)每种取值^出现次数

    考虑求出每个(I)的2^(k-1)种乘积的出现次数,然后求出FWT的积,最后IFWT还原出答案

    然而直接求出现次数不好求,考虑用FWT(第二种,不同于上面的)来搞

    因为FWT实质上是每一位乘上系数再求和,所以可以把每一位分开求

    暴力FWT时在pi,2位置上加上a2,则FWT后位置(I)的a2系数为((-1)^{|I&p_{i,2}|})

    在pi,2上+1,FWT后可以得到piFWT后第(I)位的a2系数

    若把i=1~n的pi,2都+1,FWT后得到的则是p1~nFWT后第(I)位的a2系数之和,即(I)位所乘的数中a2为正的个数-a2为负的个数

    如图,求得的东西就是第(I)位中a2的系数之和,等于正数-负数个数

    假设k=3,设x0=a1+a2+a3,x1=a1-a2+a3,x2=a1+a2-a3,x3=a1-a2-a3

    那么求得的a2正-a2负=x0+x2-x1-x3

    同理,在pi,3处+1可得x0+x1-x2-x3

    加上最初的x0+x1+x2+x3=n,一共有3条方程4个未知数,无法解

    考虑在pi,2⊕pi,3的位置+1,看看得到什么

    首先有一条式子:a&(b⊕c)=(a⊕b)&(a⊕c)

    证明:若a的某一位为0,则左右两边都为0,否则都为b⊕c

    那么FWT后第(I)位为((-1)^{|I&(p_{i,2} igoplus p_{i,3})|}),由上可知等于((-1)^{|I&(p_{i,2})|}*(-1)^{|I&(p_{i,3})|})

    把正看成0,负看成1,乘看成异或,则符号满足位运算的性质,这个东西就是a2与a3的符号的异或,求得的是(异或为正-异或为负)

    所以同上可得x0-x1-x2+x3

    推广一下,一共有2^(k-1)个未知数,枚举子集异或共有2^(k-1)-1条方程,加上∑xi=n共2^(k-1)条,可以高斯消元

    但是消元太慢了,观察一下n=4时FWT的结果

    {a,b,c,d}-->{a+b+c+d,a-b+c-d,a+b-c-d,a-b-c+d}

    和x的关系完全一致,所以把求得的方程按照顺序(-1看成1,2~k对应二进制从低到高)排好后IFWT(第三种,不同于之前的两种)即可

    证明见https://blog.csdn.net/zxyoi_dreamer/article/details/104188934

    ∑xi=n不必特判,因为当第0位为n时FWT后每一位都为n

    注意三种FWT/IFWT的大小与含义差别

    code

    #include <algorithm>
    #include <iostream>
    #include <cstring>
    #include <cstdlib>
    #include <cstdio>
    #define fo(a,b,c) for (a=b; a<=c; a++)
    #define fd(a,b,c) for (a=b; a>=c; a--)
    #define mod 998244353
    #define two 499122177
    #define file
    using namespace std;
    
    int P[10]={0,1,2,4,8,16,32,64,128,256};
    int p[1000001][10];
    long long a[21];
    long long A[1048576];
    long long b[1048576];
    long long c[1048576];
    long long p2[1048576];
    long long sum[512];
    int n,m,m2,K,k2,i,j,k,l,S;
    
    long long qpower(long long a,int b)
    {
    	long long ans=1;
    	
    	while (b)
    	{
    		if (b&1)
    		ans=ans*a%mod;
    		a=a*a%mod;
    		b>>=1;
    	}
    	
    	return ans;
    }
    
    void fwt(int st,long long *a,int N,int len,int type)
    {
    	int i,j,k,l,s1=2,s2=1,S=N;
    	long long u,v;
    	
    	fo(i,1,len)
    	{
    		S/=2;
    		fo(j,0,S-1)
    		{
    			fo(k,0,s2-1)
    			{
    				u=a[st+j*s1+k];
    				v=a[st+j*s1+k+s2];
    				
    				if (type==1)
    				a[st+j*s1+k]=(u+v)%mod,a[st+j*s1+k+s2]=(u-v)%mod;
    				else
    				a[st+j*s1+k]=(u+v)*two%mod,a[st+j*s1+k+s2]=(u-v)*two%mod;
    			}
    		}
    		s1*=2,s2*=2;
    	}
    }
    
    void dg(int t,int s1,long long s2)
    {
    	int i;
    	
    	if (t>K)
    	{
    		memset(c,0,8*m2);
    		sum[s1]=s2;
    		
    		fo(i,1,n)
    		++c[p2[i]];
    		fwt(0,c,m2,m,1);
    		
    		fo(i,0,m2-1)
    		b[i*k2+s1]=c[i];
    		return;
    	}
    	
    	dg(t+1,s1,(s2+a[t])%mod);
    	
    	fo(i,1,n) p2[i]^=p[i][t];
    	dg(t+1,s1|P[t-1],(s2-a[t])%mod);
    	fo(i,1,n) p2[i]^=p[i][t];
    }
    
    int main()
    {
    	freopen("yuyuko.in","r",stdin);
    	#ifdef file
    	freopen("yuyuko.out","w",stdout);
    	#endif
    	
    	scanf("%d%d%d",&n,&m,&K);m2=qpower(2,m),k2=qpower(2,K-1); //2^(k-1)
    	fo(i,1,K)
    	scanf("%lld",&a[i]);
    	fo(i,1,n)
    	{
    		fo(j,1,K)
    		scanf("%d",&p[i][j]);
    		
    		S^=p[i][1];
    		fd(j,K,1)
    		p[i][j]^=p[i][1];
    	}
    	
    //	---
    	
    	dg(2,0,a[1]); //1
    	
    	fo(i,0,m2-1) //2
    	{
    		fwt(i*k2,b,k2,K-1,-1);
    		
    		A[i]=1;
    		fo(j,0,k2-1)
    		A[i]=A[i]*qpower(sum[j],b[i*k2+j])%mod;
    	}
    	
    //	---
    	
    	fwt(0,A,m2,m,-1);
    	fo(i,0,m2-1)
    	printf("%lld ",(A[i^S]+mod)%mod);
    	printf("
    ");
    	
    	fclose(stdin);
    	fclose(stdout);
    	
    	return 0;
    }
    
  • 相关阅读:
    6 November in 614
    4 November in ss
    标准模板库(STL)
    类模板
    函数模板和模板函数
    关于“宏定义”的作用范围
    运算符重载
    内存分配和释放的函数
    数据库恢复的基础是利用转储的冗余数据
    在局域网络内的某台主机用ping命令测试网络连接时发现网络内部的主机都可以连同,而不能与公网连通,问题可能是
  • 原文地址:https://www.cnblogs.com/gmh77/p/12318077.html
Copyright © 2020-2023  润新知