FWT模板

我觉得那几个证明真的有点猥琐,以后有时间再搞懂吧(或许搞懂了也不会补的)

推荐博客:yyb

我觉得除了异或,结论都可以感性出来,异或也很好记。

IFWT的话就是直接反解,不需要记。

or:

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))

and:

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(A0A1),IFWT(A1))

xor:

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(A0A1))
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((A0A1)/2))

FWT或IFWT快速求一个的值:

这个东西可以做到 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]=iSA[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]=SiA[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]);
}

你可能感兴趣的:(模版,FFT,NTT,FWT……)