ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【笔记】快速莫比乌斯/沃尔什变换 (FMT/FWT)

2022-02-02 19:02:55  阅读:162  来源: 互联网

标签:begin end FMT IFWT 沃尔什 FWT cases ll


在看懂之前看大家就写了下面三个式子,感觉个个都是谜语人,然而确实只需要下面三个式子就行了...
对于 FFT,我们求的就是多项式卷积,思路是对数组变换一波,然后点乘,然后再逆变换回来

对于数组 A 和 B,求 C 定义为:$$C_i=\sum_{j\oplus k = i}A_j \times B_k$$
其中 \(\oplus\) 分别可以是 or, and, xor

要看具体说明和证明看这里,下面的只要知道一些写法的含义:\(A = (A_0, A_1, ...)\) 这种意思是数组拼接成新数组的表示方式;A_0也是数组,另外FWT(A)也是数组;A+B 表示数组的按位相加...

FMT 处理的是 or 和 and,其实就是二进制的高维前缀和、然后点乘后再差分,这里直接上式子:
设当前有 \(2^n\) 项,\(A_0\) 表示前 \(2^{n-1}\) 项,就是编号最高位为 0 的部分(别忘了下标 0, 1, ..., 2^n-1)
记 \(A'\) 为 \(FWT(A)\)

or 卷积:

\[FWT(A) = \begin{cases} (FWT(A_0), FWT(A_1)+FWT(A_0)) & (n>0) \\ A & (n=0) \end{cases} \]

\[IFWT(A') = \begin{cases} (IFWT(A'_0), IWFT(A'_1)-IWFT(A'_0)) & (n>0) \\ A' & (n=0) \end{cases} \]

and 卷积:

\[FWT(A) = \begin{cases} (FWT(A_0)+FWT(A_1), FWT(A_1)) & (n>0) \\ A & (n=0) \end{cases} \]

\[IFWT(A') = \begin{cases} (IFWT(A'_0)-IFWT(A'_1), IFWT(A'_1)) & (n>0) \\ A' & (n=0) \end{cases} \]

xor 卷积的证明以后再看...(

xor 卷积:

\[FWT(A) = \begin{cases} (FWT(A_0)+FWT(A_1), FWT(A_0)-FWT(A_1)) & (n>0) \\ A & (n=0) \end{cases} \]

\[IFWT(A') = \begin{cases} (\frac{IFWT(A'_0)+IFWT(A'_1)}{2}, \frac{IWFT(A'_0)-IFWT(A'_1)}{2}) & (n>0) \\ A' & (n=0) \end{cases} \]

模板题

#include <cstdio>
using namespace std;
typedef long long ll;
const ll mod = 998244353;
const ll inv2 = 499122177; // inv_2 of mod
const int MAXN = 200005;
int N; ll A[MAXN], B[MAXN];
struct myFWT {
	// n must be power of 2; f [0, n-1]
	int n; ll a[MAXN], b[MAXN];
	void OR(ll *f, int type) {
		for (int mid=1; mid< n; mid<<=1)
			for (int blk=(mid<<1), j=0; j< n; j+=blk)
				for (int i=j; i< j+mid; i++)
					f[i+mid] = (f[i+mid] + f[i]*type + mod) % mod;
	}
	void AND(ll *f, int type) {
		for (int mid=1; mid< n; mid<<=1)
			for (int blk=(mid<<1), j=0; j< n; j+=blk)
				for (int i=j; i< j+mid; i++)
					f[i] = (f[i] + f[i+mid]*type + mod) % mod;
	}
	void XOR(ll *f, int type) {
		for (int mid=1; mid< n; mid<<=1)
			for (int blk=(mid<<1), j=0; j< n; j+=blk)
				for (int i=j; i< j+mid; i++) {
					ll x = f[i], y = f[i+mid];
					f[i] = (x+y) % mod * (type==1?1:inv2) % mod;
					f[i+mid] = (x-y+mod) % mod * (type==1?1:inv2) % mod;
				}
	}
	void init() {
		for (int i=0; i< n; i++) a[i] = A[i], b[i] = B[i];
	}
	void print() {
		for (int i=0; i< n; i++) printf("%lld ", a[i]); printf("\n");
	}
	void workOR () {
		init(), OR(a, 1), OR(b, 1);
		for (int i=0; i< n; i++) a[i] = a[i] * b[i] % mod;
		OR(a, -1), print();
	}
	void workAND() {
		init(), AND(a, 1), AND(b, 1);
		for (int i=0; i< n; i++) a[i] = a[i] * b[i] % mod;
		AND(a, -1), print();
	}
	void workXOR() {
		init(), XOR(a, 1), XOR(b, 1);
		for (int i=0; i< n; i++) a[i] = a[i] * b[i] % mod;
		XOR(a, -1), print();
	}
} fwt;
int main()
{
	scanf("%d", &N); N = 1<<N, fwt.n = N;
	for (int i=0; i< N; i++) scanf("%lld", &A[i]), A[i] %= mod;
	for (int i=0; i< N; i++) scanf("%lld", &B[i]), B[i] %= mod;
	fwt.workOR(), fwt.workAND(), fwt.workXOR();
}

标签:begin,end,FMT,IFWT,沃尔什,FWT,cases,ll
来源: https://www.cnblogs.com/zhyh/p/15860616.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有