快速沃尔什变换(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?'
':' ');
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?'
':' ');
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)=(... , ...) 使满足上述条件

基础部分

公式推导

 

 验证公式正确性

原文地址:https://www.cnblogs.com/cmyg/p/10424145.html