FWT 整理

FWT 整理

以前我记得是正式写过 FWT 的总结的但是貌似没找到

作为一个背板选手详细证明被咕咕咕了,可以见 LSJ的blog)

注意几种卷积都满足可加性。

或卷积

或的 FWT 是:

也就是 每个数的子集和。

或卷积满足

也就是说后一半加上前一半,代码长这样:

1
2
3
4
5
6
inline void FWTor(ll a[], int len) {
for (int mid = 2; mid <= len; mid <<= 1)
for (int i = 0; i < len; i += mid)
for (int j = i; j < i + (mid >> 1); j++)
( a[j + (mid >> 1)] += a[j] ) %= P;
}

与卷积

与的 FWT 是:

也就是说是 每个数的超集的和。

与卷积是:

也就是前一半分别加上后一半,代码长这样:

1
2
3
4
5
6
inline void FWTand(ll a[], int len) {
for (int mid = 2; mid <= len; mid <<= 1)
for (int i = 0; i < len; i += mid)
for (int j = i; j < i + (mid >> 1); j++)
( a[j] += a[j + (mid >> 1)] ) %= P;
}

与卷积和或卷积的逆运算

最后推出的结论是,它们正好是把原来的卷积的 加减号 取反。详细证明不想写了。。

1
2
3
4
5
6
inline void IFWTor(ll a[], int len) {
for (int mid = 2; mid <= len; mid <<= 1)
for (int i = 0; i < len; i += mid)
for (int j = i; j < i + (mid >> 1); j++)
( a[j + (mid >> 1)] += P - a[j] ) % P;
}
1
2
3
4
5
6
inline void IFWTand(ll a[], int len) {
for (int mid = 2; mid <= len; mid <<= 1)
for (int i = 0; i < len; i += mid)
for (int j = i; j < i + (mid >> 1); j++)
( a[j] += P - a[j + (mid >> 1)] ) % P;
}

异或卷积

这个的 FWT 是最离谱的,

也就是说每个数字的系数是它和 $i$ 的共同的 1 的个数的奇偶行

关于 xor 卷积的递推:

也就是,前一半变成前面和后面的和,后一半变成前面和后面的差。代码长这样:

1
2
3
4
5
6
7
8
inline void FWTxor(ll a[], int len) {
for (int mid = 2; mid <= len; mid <<= 1)
for (int i = 0; i < len; i += mid)
for (int j = i; j < i + (mid >> 1); j++) {
ll x = a[j], y = a[j + (mid >> 1)];
a[j] = ( x + y ) % P, a[j + (mid >> 1)] = ( x - y + P ) % P;
}
}

关于 xor 的逆卷积,推出来是

就相当于前一半变成相加除以二,后一半变成相减除以二。

1
2
3
4
5
6
7
8
9
inline void IFWTxor(ll a[], int len) {
for (int mid = 2; mid <= len; mid <<= 1)
for (int i = 0; i < len; i += mid)
for (int j = i; j < i + (mid >> 1); j++) {
ll x = a[j], y = a[j + (mid >> 1)];
// a[j] = (x + y) >> 1, a[j + (mid >> 1)] = (x - y) >> 1;
a[j] = 1ll * ( x + y ) * inv2 % P , a[j + (mid >> 1)] = 1ll * (x - y) * inv2 % P;
}
}
文章作者: yijan
文章链接: https://yijan.co/fwt-zheng-li/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Yijan's Blog