【笔记】FWT 快速沃尔什变换

参考资料

学习笔记1
学习笔记2

题目汇总

  • bzoj4589 Hard Nim
    设每堆石子个数是a1,a2,a3...ak,先手必胜的条件是a1 xor a2 xor a3 ... ak == 0
    fwt可以计算下标求xor 等于一个定值的数的乘积的和, 因为要求所有石子堆数都是质数,所以给要卷积的数组,质数赋值为1,合数赋值为0,这样只有所有的数字都是1乘积才为1,求和后就是总的方案数
  • 51nod1773 A国的贸易
    每过一天,城市i的商品数就变成a[i] = a[i] + ∑a[j] (j xor i==2^m)
    令b数组为b[0]=1,b[2^m]=1,其余为0
    异或具有自反性质,所以 a[k] = ∑ a[i]*b[j] (i xor j = k) 当j为2^m时b才为1
    这满足fwt_xor 应用条件,t天就乘t个b,用快速幂加速即可
  • 牛客多校第九场A Circulant Matrix 纯裸沙比题,不放代码了
  • 2018沈阳onsite I Distance Between Sweethearts 博客有题解

模板

最常见的是 xor 题目,结合自反性质构造卷积式

void fwt_xor(ll a[], int len, int on){
	int inv2 = 500000004;
	for (int i = 1; i < len; i <<= 1)
		for (int p = i<<1, j = 0;j < len; j += p)
			for (int k = 0; k < i; k++) {
				int x = a[j + k], y = a[i + j + k];
				a[j + k] = (x + y) % MOD;
				a[j + k + i] = (x - y + MOD) % MOD;
				if (on == -1) {
					a[j + k] = a[j + k] * inv2 % MOD;
					a[i + j + k] = a[i + j + k] * inv2 % MOD;
				}
			}
}
void fwt(ll a[],int n,int v) {
    for(int d=1;d<n;d<<=1) {
	for(int m = d<<1,i=0;i<n;i+=m) {
	    for(int j=0;j<d;j++){
		ll x = a[i+j],y = a[i+j+d];
		if(v == 1) a[i+j] = (x+y),a[i+j+d] = (x-y);
		else a[i+j] = (x+y)/2,a[i+j+d] = (x-y)/2;
	    }
	}
    }
}

此外还有 or 以及 and 的代码 (未使用过)

void fwt_and(ll a[], int len, int on)
{
    for(int i = 1;i < len;i <<= 1)
        for(int p = i << 1, j = 0; j < len; j += p)
            for(int k = 0; k < i; k++)
                if(on == 1)a[j + k]=(a[j + k] + a[i + j + k]) % MOD;
                else a[j + k]=(a[j + k] + MOD - a[i + j + k]) % MOD;
}
void fwt_or(ll a[], int len, int on)
{
    for(int i = 1;i < len;i <<= 1)
        for(int p = i << 1, j = 0; j < len; j += p)
            for(int k = 0; k < i; k++)
                if(on == 1)a[i + j + k]=(a[j + k] + a[i + j + k]) % MOD;
                else a[i + j + k]=(a[i + j + k] + MOD - a[j + k]) % MOD;
}
posted @ 2018-08-17 16:23  Greenty  阅读(275)  评论(0编辑  收藏  举报