能轻松背板子的FWT(快速沃尔什变换)

FWT应用

我不知道\(FWT\)的严格定义
百度百科和维基都不知道给一坨什么**东西

FWT(Fast Walsh Fransform),中文名快速沃尔什变换
然后我也不知道\(FWT\)到底是什么
你们怎么念FWT的反正我念扶卧塔

\(FFT\)当然可以做多项式卷积
形如\(C(k)=\sum_{i+j=k}f[i]g[j]\),很简单,大家都会
由于有这个性质所以也可做分治\(FFT\)

但是如果把\(i+j\)换一下操作符
变成\(C(k)=\sum_{i???j=k}f[i]g[j]\)
其中\(???\)可以是\(or,and,xor\)三种运算
这时就要用\(FWT\)来做特殊卷积了


结论

类似\(FFT\),把当前多项式\(A\)拆成前一半\(A_0\)和后一半\(A_1\)
注意不是奇数项和偶数项,只是前一半和后一半……(狗头保命)
也可知\(FWT\)也只能处理长度为\(2\)的次幂的多项式

or

\[FWT(A)=merge(FWT(A_0),FWT(A_0)+FWT(A_1)) \]

\[IFWT(A)=merge(IFWT(A_0),IFWT(A_0)-IFWT(A_1)) \]

and

\[FWT(A)=merge(FWT(A_0)+FWT(A_1),FWT(A_1)) \]

\[IFWT(A)=merge(IFWT(A_0)-IFWT(A_1),IFWT(A_1)) \]

xor

\[FWT(A)=merge(FWT(A_0)+FWT(A_1),FWT(A_0)-FWT(A_1)) \]

\[IFWT(A)=merge({{IFWT(A_0)+IWFT(A_1)}\over 2},{IFWT(A_0)-IFWT(A_1)\over 2}) \]

\(+\)就是每一位值加起来,不知道\(merge\)是什么东西?
其实就是两个多项式前后拼起来……(狗头保命)
所以就算不清楚原理背下结论也很容易写出板子
由于某些原因原理完全可以跳过不看
但还是懂一下比较好


原理

清真のor&and

\(FWT(A)=A',A'[i]=\sum_{i|j=i}A[j]\)\(B\)同理
\(i|j=i\)就表示二进制下\(j\)一定是\(i\)的子集
这样好像可以满足\(C'[i]=A'[i]*B'[i]\),不懂可以写一写
大概就是\(A'[i]\)已经包含下标或起来\(=i\)\(A\)\(B'[i]\)也是
所以\(A'[i],B'[i]\)里包含的每个数下标或起来都等于\(i\)
自然两个和乘起来就是两两配对的总和,即\(C'[i]=A'[i]*B'[i]\)

肯定不能枚举\(i\)的二进制子集因为太沙雕
然后试着把\(A\)拆成前半段\(A_0\)和后半段\(A_1\)
如果知道\(FWT(A_0),FWT(A_1)\),可以知道\(FWT(A)\)
是个学过FFT的人都知道应该可以

设当前多项式\(A\)的长度为\(2^k\)\(A_0,A_1\)长度为\(2^{k-1}\)
\(FWT(A)\)的前半段表示\(A\)的二进制位第\(k\)位填\(0\)
那么是它子集的好像\(FWT(A_0)\)
\(FWT(A)\)的前半段表示\(A\)的二进制位第\(k\)位填\(1\)
是它子集的不仅有\(FWT(A_1)\),还有\(FWT(A_0)\)
大概就是这个亚子其实我也不是很清楚
所以\(FWT(A)\)前半段就是\(FWT(A_0)\),后半段就是\(FWT(A_0),FWT(A_1)\)加起来
于是就有了结论的\(FWT(A)=merge(FWT(A_0),FWT(A_0)+FWT(A_1))\)

至于\(IFWT\),就是已知\(A_0',A_1'\),求\(A_0,A_1\)
由于\(A_0'=A_0,A_1'=A_0+A_1\),所以\(A_0=A_0',A_1=A_1'-A_0'\)
这样就有了两个简单易懂易背的结论

对于\(and\)也可同理推一波操作,和\(or\)很像,结论、代码也很像
打对\(or\)就可以打对\(and\).jpg

鬼畜のxor

一看\(or\)\(and\)的结论就很清真,其实是因为\(or\)\(and\)很像
\(xor\)奇怪就奇怪在运算和\(or,and\)有很大区别
\(xor\)卷积还是有优化的方法

\(i\&j\)\(1\)数量的奇偶性为\(i\)\(j\)的奇偶性,那么\(i\)\(k\)的奇偶性异或\(j\)\(k\)的奇偶性等于\(i⊕j\)\(k\)的奇偶性
\(f(x)\)表示\(x\)在二进制下\(1\)的个数

\[A'[i]=\sum_{f(i\&j)mod2=0}A[j]-\sum_{f(i\&j)mod2=1}A[j] \]

如果这样的话

\[FWT(A)=merge(FWT(A_1)-FWT(A_0),FWT(A_1)+FWT(A_0)) \]

\[IFWT(A)=merge({{IFWT(A_1)-IWFT(A_0)}\over 2},{IFWT(A_1)+IFWT(A_0)\over 2}) \]

对于\(or\),由于\(or,and\)同理,令

\[A'[i]=\sum_{f(i|j)mod2=0}A[j]-\sum_{f(i|j)mod2=1}A[j] \]

结果和上面的是一样的
于是由这两种运算的优美性质自然而然的可以得到xor的规律
于是你就知道为什么xor那么鬼畜


FWT板子

#define mod 998244353 
#define inv2 499122177
inline void fwt_or(ll f[],ll len,ll inv)
{
	for (ll i=1;i<len;i<<=1)
		for (ll j=0;j<len;j+=(i<<1))
			for (ll k=0;k<i;++k)
				f[i+j+k]=(inv*f[j+k]+f[i+j+k]+mod)%mod;
}
inline void fwt_and(ll f[],ll len,ll inv)
{
	for (ll i=1;i<len;i<<=1)
		for (ll j=0;j<len;j+=(i<<1))
			for (ll k=0;k<i;++k)
				f[j+k]=(f[j+k]+inv*f[i+j+k]+mod)%mod;
}
inline void fwt_xor(ll f[],ll len,ll inv)
{
	for (ll i=1;i<len;i<<=1)
		for (ll j=0;j<len;j+=(i<<1))
			for (ll k=0;k<i;++k)
			{
				ll x=f[j+k],y=f[i+j+k];
				f[j+k]=(x+y)%mod,f[i+j+k]=(x-y+mod)%mod;
				if (inv==-1)(f[j+k]*=inv2)%=mod,(f[i+j+k]*=inv2)%=mod;
			}
}

FWT搞完

本人版权意识薄弱……

别人早就会的东西我现在才学
\(FFT\)都会了一年了我才懂\(FWT\)
原因还是我太蔡了

posted @ 2019-09-06 20:59  路人黑的纸巾  阅读(352)  评论(0编辑  收藏  举报