快速沃尔什变换(FWT) 与 快速莫比乌斯变换 与 快速沃尔什变换公式推导
后面的图片将会告诉:
如何推出FWT的公式tf
如何推出FWT的逆公式utf
用的是设系数,求系数的方法!
=========================================================
以一种高度思考
http://picks.logdown.com/posts/179290-fast-walsh-hadamard-transform
加和乘的定义
大小为1时的公式
https://blog.csdn.net/zhshrs/article/details/54838466
证明
https://blog.csdn.net/john123741/article/details/76576925
写成
or
tf(A)=(tf(A0),tf(A1)+tf(A0))
utf(A)=(utf(A0),utf(A1)-utf(A0))
and
tf(A)=(tf(A0)+tf(A1),tf(A1))
utf(A)=(utf(A0)-utf(A1),utf(A1))
xor
tf(A)=(tf(A0)+tf(A1),tf(A0)-tf(A1))
utf(A)=(1/2*(utf(A0)+utf(A1)),1/2*(utf(A0)-utf(A1)))
更好记忆一点
对于or,and
0 = 0 or 0 对应 or tf(A0)[utf(A0)]
1 = 1 and 1 对应 and tf(A1)[utf(A1)]
=================================
and or xor 二进制操作
0~2^(k-1)-1时,最高位为0
2^(k-1)~2^k-1时,最高位为1
e.g.
000
001
010
011
----
100
101
110
111
P.S.:
FFT和FWT,两者虽然实现方法都是内容分半(二分),但是其本质原理不同。
FFT: http://www.cnblogs.com/zwfymqz/p/8244902.html
快速莫比乌斯变换
study from :
https://yhx-12243.github.io/OI-transit/records/vijos%20%234.html
适用于and or,xor 行不通
FMT写法和FWT是一样的,两者考虑问题角度不一样。
https://www.luogu.org/problemnew/show/P4717
存储函数地址
void (*addr1[3])(ll a[])={fwt1,fwt2,fwt3};
void (*addr2[3])(ll a[])={ufwt1,ufwt2,ufwt3};
also can use (int type)=1ll*...
注意当数字范围为[0,x]
遍历范围 [0,z) tot=2*x(大于any i op j, 其中i,j in [0,x])
而数组开z大小
对于代码中的tot,要写成2^k的形式,
否则如写成tot,e.g. tot=9, 8(i)+3(j)>9。
对应好记忆
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cmath> 4 #include <cstring> 5 #include <string> 6 #include <algorithm> 7 #include <iostream> 8 using namespace std; 9 #define ll long long 10 11 const double eps=1e-8; 12 const ll inf=1e9; 13 const ll mod=998244353; 14 const int maxn=(1<<17)*2; ///any n or <2n 15 16 /** 17 补全为2^k 18 **/ 19 20 ll aa[maxn],bb[maxn],a[maxn],b[maxn]; 21 int tot; 22 ll mod_inv_2=(mod+1)/2; 23 24 ///or 25 void fwt1(ll *a) 26 { 27 int cnt_pre,cnt_cur,i,j; 28 for (cnt_pre=1,cnt_cur=2;cnt_pre<tot;cnt_pre<<=1,cnt_cur<<=1) 29 for (i=0;i<tot;i+=cnt_cur) 30 for (j=0;j<cnt_pre;j++) 31 (a[i+j+cnt_pre]+=a[i+j])%=mod; 32 } 33 34 void ufwt1(ll *a) 35 { 36 int cnt_pre,cnt_cur,i,j; 37 for (cnt_pre=tot>>1,cnt_cur=tot;cnt_pre>0;cnt_pre>>=1,cnt_cur>>=1) 38 // for (cnt_pre=1,cnt_cur=2;cnt_pre<tot;cnt_pre<<=1,cnt_cur<<=1) 39 for (i=0;i<tot;i+=cnt_cur) 40 for (j=0;j<cnt_pre;j++) 41 (a[i+j+cnt_pre]-=a[i+j]-mod)%=mod; 42 } 43 44 ///and 45 void fwt2(ll *a) 46 { 47 int cnt_pre,cnt_cur,i,j; 48 for (cnt_pre=1,cnt_cur=2;cnt_pre<tot;cnt_pre<<=1,cnt_cur<<=1) 49 for (i=0;i<tot;i+=cnt_cur) 50 for (j=0;j<cnt_pre;j++) 51 (a[i+j]+=a[i+j+cnt_pre])%=mod; 52 } 53 54 void ufwt2(ll *a) 55 { 56 int cnt_pre,cnt_cur,i,j; 57 for (cnt_pre=tot>>1,cnt_cur=tot;cnt_pre>0;cnt_pre>>=1,cnt_cur>>=1) 58 // for (cnt_pre=1,cnt_cur=2;cnt_pre<tot;cnt_pre<<=1,cnt_cur<<=1) 59 for (i=0;i<tot;i+=cnt_cur) 60 for (j=0;j<cnt_pre;j++) 61 (a[i+j]-=a[i+j+cnt_pre]-mod)%=mod; 62 } 63 64 ///xor 65 void fwt3(ll *a) 66 { 67 int cnt_pre,cnt_cur,i,j; 68 ll x; 69 for (cnt_pre=1,cnt_cur=2;cnt_pre<tot;cnt_pre<<=1,cnt_cur<<=1) 70 for (i=0;i<tot;i+=cnt_cur) 71 for (j=0;j<cnt_pre;j++) 72 { 73 x=a[i+j]; 74 a[i+j]=(a[i+j]+a[i+j+cnt_pre])%mod; 75 a[i+j+cnt_pre]=(x-a[i+j+cnt_pre]+mod)%mod; 76 } 77 } 78 79 void ufwt3(ll *a) 80 { 81 int cnt_pre,cnt_cur,i,j; 82 ll x; 83 for (cnt_pre=tot>>1,cnt_cur=tot;cnt_pre>0;cnt_pre>>=1,cnt_cur>>=1) 84 // for (cnt_pre=1,cnt_cur=2;cnt_pre<tot;cnt_pre<<=1,cnt_cur<<=1) 85 for (i=0;i<tot;i+=cnt_cur) 86 for (j=0;j<cnt_pre;j++) 87 { 88 x=a[i+j]; 89 a[i+j]=(a[i+j]+a[i+j+cnt_pre])*mod_inv_2%mod; 90 a[i+j+cnt_pre]=(x-a[i+j+cnt_pre]+mod)*mod_inv_2%mod; ///x- 91 } 92 } 93 94 int main() 95 { 96 int n,i,j; 97 scanf("%d",&n); 98 tot=1<<n; 99 for (i=0;i<tot;i++) 100 scanf("%lld",&aa[i]); 101 for (i=0;i<tot;i++) 102 scanf("%lld",&bb[i]); 103 104 105 void (*addr1[3]) (ll a[])={fwt1,fwt2,fwt3}; 106 void (*addr2[3]) (ll a[])={ufwt1,ufwt2,ufwt3}; 107 108 for (i=0;i<3;i++) 109 { 110 memcpy(a,aa,sizeof(aa)); 111 memcpy(b,bb,sizeof(bb)); 112 (*addr1[i])(a); 113 (*addr1[i])(b); 114 for (j=0;j<tot;j++) 115 a[j]=a[j]*b[j]%mod; 116 (*addr2[i])(a); 117 for (j=0;j<tot;j++) 118 printf("%lld%c",a[j],j==tot-1?'\n':' '); 119 } 120 return 0; 121 } 122 /* 123 0 124 1000000 125 1000000 126 127 3 128 1 1 1 1 1 1 1 1 129 1 1 1 1 1 1 1 1 130 */
对应下方的图片公式推导
tf a0+a1 a1-a0
utf a1 a0
1 #include <cstdio> 2 #include <cstdlib> 3 #include <cmath> 4 #include <cstring> 5 #include <string> 6 #include <algorithm> 7 #include <iostream> 8 using namespace std; 9 #define ll long long 10 11 const double eps=1e-8; 12 const ll inf=1e9; 13 const ll mod=998244353; 14 const int maxn=(1<<17)*2; ///any n or <2n 15 16 /** 17 补全为2^k 18 **/ 19 20 ll aa[maxn],bb[maxn],a[maxn],b[maxn]; 21 int tot; 22 ll mod_inv_2=(mod+1)/2; 23 24 ///or 25 void fwt1(ll *a) 26 { 27 int cnt_pre,cnt_cur,i,j; 28 for (cnt_pre=1,cnt_cur=2;cnt_pre<tot;cnt_pre<<=1,cnt_cur<<=1) 29 for (i=0;i<tot;i+=cnt_cur) 30 for (j=0;j<cnt_pre;j++) 31 (a[i+j+cnt_pre]+=a[i+j])%=mod; 32 } 33 34 void ufwt1(ll *a) 35 { 36 int cnt_pre,cnt_cur,i,j; 37 for (cnt_pre=tot>>1,cnt_cur=tot;cnt_pre>0;cnt_pre>>=1,cnt_cur>>=1) 38 // for (cnt_pre=1,cnt_cur=2;cnt_pre<tot;cnt_pre<<=1,cnt_cur<<=1) 39 for (i=0;i<tot;i+=cnt_cur) 40 for (j=0;j<cnt_pre;j++) 41 (a[i+j+cnt_pre]-=a[i+j]-mod)%=mod; 42 } 43 44 ///and 45 void fwt2(ll *a) 46 { 47 int cnt_pre,cnt_cur,i,j; 48 for (cnt_pre=1,cnt_cur=2;cnt_pre<tot;cnt_pre<<=1,cnt_cur<<=1) 49 for (i=0;i<tot;i+=cnt_cur) 50 for (j=0;j<cnt_pre;j++) 51 (a[i+j]+=a[i+j+cnt_pre])%=mod; 52 } 53 54 void ufwt2(ll *a) 55 { 56 int cnt_pre,cnt_cur,i,j; 57 for (cnt_pre=tot>>1,cnt_cur=tot;cnt_pre>0;cnt_pre>>=1,cnt_cur>>=1) 58 // for (cnt_pre=1,cnt_cur=2;cnt_pre<tot;cnt_pre<<=1,cnt_cur<<=1) 59 for (i=0;i<tot;i+=cnt_cur) 60 for (j=0;j<cnt_pre;j++) 61 (a[i+j]-=a[i+j+cnt_pre]-mod)%=mod; 62 } 63 64 ///xor 65 void fwt3(ll *a) 66 { 67 int cnt_pre,cnt_cur,i,j; 68 ll x; 69 for (cnt_pre=1,cnt_cur=2;cnt_pre<tot;cnt_pre<<=1,cnt_cur<<=1) 70 for (i=0;i<tot;i+=cnt_cur) 71 for (j=0;j<cnt_pre;j++) 72 { 73 x=a[i+j]; 74 (a[i+j]+=a[i+j+cnt_pre])%=mod; 75 (a[i+j+cnt_pre]-=x-mod)%=mod; ///-x 76 } 77 } 78 79 void ufwt3(ll *a) 80 { 81 int cnt_pre,cnt_cur,i,j; 82 ll x; 83 for (cnt_pre=tot>>1,cnt_cur=tot;cnt_pre>0;cnt_pre>>=1,cnt_cur>>=1) 84 // for (cnt_pre=1,cnt_cur=2;cnt_pre<tot;cnt_pre<<=1,cnt_cur<<=1) 85 for (i=0;i<tot;i+=cnt_cur) 86 for (j=0;j<cnt_pre;j++) 87 { 88 x=a[i+j]; 89 a[i+j]=(a[i+j]+a[i+j+cnt_pre])*mod_inv_2%mod; 90 a[i+j+cnt_pre]=(x-a[i+j+cnt_pre]+mod)*mod_inv_2%mod; ///x- 91 } 92 } 93 94 int main() 95 { 96 int n,i,j; 97 scanf("%d",&n); 98 tot=1<<n; 99 for (i=0;i<tot;i++) 100 scanf("%lld",&aa[i]); 101 for (i=0;i<tot;i++) 102 scanf("%lld",&bb[i]); 103 104 105 void (*addr1[3]) (ll a[])={fwt1,fwt2,fwt3}; 106 void (*addr2[3]) (ll a[])={ufwt1,ufwt2,ufwt3}; 107 108 for (i=0;i<3;i++) 109 { 110 memcpy(a,aa,sizeof(aa)); 111 memcpy(b,bb,sizeof(bb)); 112 (*addr1[i])(a); 113 (*addr1[i])(b); 114 for (j=0;j<tot;j++) 115 a[j]=a[j]*b[j]%mod; 116 (*addr2[i])(a); 117 for (j=0;j<tot;j++) 118 printf("%lld%c",a[j],j==tot-1?'\n':' '); 119 } 120 return 0; 121 } 122 /* 123 0 124 1000000 125 1000000 126 127 3 128 1 1 1 1 1 1 1 1 129 1 1 1 1 1 1 1 1 130 */
and,or,xor等操作
C=A@B @为卷积运算(通过两个函数生成第三个函数的一种数学算子)
目标:tf(C)=tf(A)*tf(B)
设置tf(X)=(... , ...) 使满足上述条件
基础部分
公式推导
验证公式正确性