我觉得那几个证明真的有点猥琐,以后有时间再搞懂吧(或许搞懂了也不会补的)
推荐博客:yyb
我觉得除了异或,结论都可以感性出来,异或也很好记。
IFWT的话就是直接反解,不需要记。
F W T ( A ) = ( F W T ( A 0 ) , F W T ( A 0 + A 1 ) ) FWT(A)=(FWT(A0),FWT(A0+A1)) FWT(A)=(FWT(A0),FWT(A0+A1))
I F W T ( A ) = ( I F W T ( A 0 ) , I F W T ( − A 0 + A 1 ) ) IFWT(A)=(IFWT(A0),IFWT(-A0+A1)) IFWT(A)=(IFWT(A0),IFWT(−A0+A1))
F W T ( A ) = ( F W T ( A 0 + A 1 ) , F W T ( A 1 ) ) FWT(A)=(FWT(A0+A1),FWT(A1)) FWT(A)=(FWT(A0+A1),FWT(A1))
I F W T ( A ) = ( I F W T ( A 0 − A 1 ) , I F W T ( A 1 ) ) IFWT(A)=(IFWT(A0-A1),IFWT(A1)) IFWT(A)=(IFWT(A0−A1),IFWT(A1))
F W T ( A ) = ( F W T ( A 0 + A 1 ) , F W T ( A 0 − A 1 ) ) FWT(A)=(FWT(A0+A1),FWT(A0-A1)) FWT(A)=(FWT(A0+A1),FWT(A0−A1))
I F W T ( A ) = ( I F W T ( ( A 0 + A 1 ) / 2 ) , I F W T ( ( A 0 − A 1 ) / 2 ) ) IFWT(A)=(IFWT((A0 + A1) / 2),IFWT((A0-A1)/2)) IFWT(A)=(IFWT((A0+A1)/2),IFWT((A0−A1)/2))
这个东西可以做到 O ( n ) O(n) O(n)
XHM给出的做法是模拟,以异或的FWT为例:
首先要明确的一点这个分治其实就是对每一位0,1的情况讨论
观察系数,可以得出,只有两位都是1的会有-1的系数,所以:
设S表示要求的那一个位置: D F T ( A ) [ S ] = ∑ i A [ i ] ∗ ( − 1 ) ∣ S a n d i ∣ DFT(A)[S]=\sum_i A[i]*{(-1)^{|S~and~i|}} DFT(A)[S]=∑iA[i]∗(−1)∣S and i∣
如果是IDFT,再除以 2 t p 2^{tp} 2tp即可。
or的FWT:
其实这个本质上是在做子集统计,那么枚举子集即可。
IFWT,通过同样的推理可以得到: I D F T ( A ) [ S ] = ∑ i ∈ S A [ i ] ∗ ( − 1 ) ∣ S x o r i ∣ IDFT(A)[S]=\sum_{i∈S} A[i]*{(-1)^{|S~xor~i|}} IDFT(A)[S]=∑i∈SA[i]∗(−1)∣S xor i∣
and的FWT:
这个本质上在做超集统计,枚举超集即可:
IFWT,通过同样的推理可以得到几乎同样的式子: I D F T ( A ) [ S ] = ∑ S ∈ i A [ i ] ∗ ( − 1 ) ∣ S x o r i ∣ IDFT(A)[S]=\sum_{S∈i} A[i]*{(-1)^{|S~xor~i|}} IDFT(A)[S]=∑S∈iA[i]∗(−1)∣S xor i∣
枚举子集、超集代码:
int S = 7, tp = 3;
for(int i = S; i; i = -- i & S)
printf("%d\n", i); //枚举子集
for(int i = S; i < (1 << tp); i = ++ i | S)
printf("%d\n", i); //枚举超集
#include
#define ll long long
#define fo(i, x, y) for(int i = x; i <= y; i ++)
#define ff(i, x, y) for(int i = x; i < y; i ++)
using namespace std;
const int N = 1 << 17;
ll a[N], b[N], c[N]; int tp;
void dft_or(ll *a, int tp, int F) {
int n = 1 << tp;
for(int h = 1; h < n; h *= 2)
for(int j = 0; j < n; j += 2 * h) {
ll *l = a + j, *r = a + j + h;
ff(i, 0, h) *r = *l * F + *r, l ++, r ++;
}
}
void dft_and(ll *a, int tp, int F) {
int n = 1 << tp;
for(int h = 1; h < n; h *= 2)
for(int j = 0; j < n; j += 2 * h) {
ll *l = a + j, *r = a + j + h;
ff(i, 0, h) *l = *l + *r * F, l ++, r ++;
}
}
void dft_xor(ll *a, int tp, int F) {
int n = 1 << tp;
for(int h = 1; h < n; h *= 2)
for(int j = 0; j < n; j += 2 * h) {
ll A, *l = a + j, *r = a + j + h;
ff(i, 0, h) {
A = *r, *r = *l - A, *l = *l + A;
if(F == -1) *l /= 2, *r /= 2;
l ++, r ++;
}
}
}
void fft(ll *a, ll *b, int tp) {
int n = 1 << tp;
dft_xor(a, tp, 1); dft_xor(b, tp, 1);
ff(i, 0, n) a[i] = a[i] * b[i];
dft_xor(a, tp, -1);
}
int main() {
a[0] = a[1] = a[2] = b[0] = b[1] = 1;
tp = 3;
ff(i, 0, 1 << tp) ff(j, 0, 1 << tp)
c[i ^ j] += a[i] * b[j];
ff(i, 0, 1 << tp) printf("%lld ", c[i]); printf("\n");
fft(a, b, 3);
ff(i, 0, 1 << tp) printf("%lld ", a[i]);
}