FWT快速沃尔什变换

处理位运算类卷积,板子很简单,就是需要记住正变换和逆变换的参数

来看一道异或的例题
FWT快速沃尔什变换_第1张图片
给一堆数,他们两两异或,能得到的不同值有多少种?这个数据量,用常规思路根本没法做的。

但是卷积是一个很神奇的东西,你把他变换到值域上再做,复杂度就能神奇地降到 n l o g n nlogn nlogn了,具体证明很复杂,可以去看oiwiki。

然后这里的具体做法就是先把元素弄到值域上,就是映射到 c n t cnt cnt数组,然后变换到值域上,卷积,再逆变换回来。中间那个 a i = a i ∗ a i a_i=a_i*a_i ai=aiai就是自己和自己卷积.正变换的参数是1,逆变换的参数是 1 / 2 1/2 1/2,当然这里都是模意义下的,需要逆元

最后得到的数组中, a i a_i ai表示异或值为 i i i的方案数。我们只要看这这个数组有多少个非零位置,就是异或得到的不同值的个数了。

如果求的是异或得到 i i i的方案数,那么就是 a i a_i ai

void XorFWT(vector &a, ll type,int P) {
    int n = a.size();
    for (ll x = 2; x <= n; x <<= 1) {
        ll k = x >> 1;
        for (ll i = 0; i < n; i += x) {
            for (ll j = 0; j < k; j++) {
                (a[i + j] += a[i + j + k]) %= P;
                (a[i + j + k] = a[i + j] - a[i + j + k] * 2) %= P;
                (a[i + j] *= type) %= P;
                (a[i + j + k] *= type) %= P;
            }
        }
    }
}
void solve(){
	cin>>n;
	int mx=1<<20;
	vi a(mx);
	rep(i,1,n){
		int x;
		cin>>x;
		a[x]=1;
	}
	XorFWT(a,1,M2);
	rep(i,0,mx-1){
		a[i]=a[i]*a[i]%M2;
	}
	XorFWT(a,(M2+1)/2,M2);
	int ans=0;
	rep(i,0,mx-1){
		ans+=a[i]>0;
	}
	cout<

如果是按位与和按位或,更换一下变换的函数即可,正变换参数仍然是1,逆变换参数是-1

附上按位与和按位或的变换板子,其实就是oiwiki的稍微改了改,oiwiki这个板子难得的写的很好,居然封装好了

//异或 正1逆1/2
void Xor(vector&a, ll type,int P) {
  for (ll x = 2; x <= n; x <<= 1) {
    ll k = x >> 1;
    for (ll i = 0; i < n; i += x) {
      for (ll j = 0; j < k; j++) {
        (a[i + j] += a[i + j + k]) %= P;
        (a[i + j + k] = a[i + j] - a[i + j + k] * 2) %= P;
        (a[i + j] *= type) %= P;
        (a[i + j + k] *= type) %= P;
      }
    }
  }
}
//与 正1逆-1
void And(vector&a, ll type,ll P) {
  for (ll x = 2; x <= n; x <<= 1) {
    ll k = x >> 1;
    for (ll i = 0; i < n; i += x) {
      for (ll j = 0; j < k; j++) {
        (a[i + j] += a[i + j + k] * type) %= P;
      }
    }
  }
}
//或 正1逆-1
void Or(vector&a, ll type,ll P) {  // 迭代实现,常数更小
  for (ll x = 2; x <= n; x <<= 1) {
    ll k = x >> 1;
    for (ll i = 0; i < n; i += x) {
      for (ll j = 0; j < k; j++) {
        (a[i + j + k] += a[i + j] * type) %= P;
      }
    }
  }
}

你可能感兴趣的:(算法)