FWT学习笔记。

由于一些奇怪的xp要求,在运算时我们需要位运算卷积。
于是就有了FWT!
FWT是用来处理一些位运算多项式的卷积,然后依然是分治形式,形如\(or,and,xor\)等位运算,先用个$\otimes $表示,大概就是

\[c_k=\sum\limits_{i\otimes j=k}a_i*b_j \]

这个亚子。

or卷积

\[c_k=\sum\limits_{i|j=k}a_i*b_j \]

写成向量就是:

\[A|B=(\sum\limits_{i|j=0}A_i*B_j,\sum\limits_{i|j=1}A_i*b_j,...,) \]

满足交换律和结合律
对于或卷积有:

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

关于证明:
别问,问就是不会证

and卷积

\[c_k=\sum\limits_{i\&j=k}A_i*B_j \]

写成向量就是:

\[A\&B=(\sum\limits_{i\&j=0}A_i*B_j,\sum\limits_{i\&j=1}A_i*b_j,...,) \]

依然满足交换律和结合律
对于与卷积有:

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

xor卷积

由于^符号过于难打于是用\(\otimes\)表示

\[c_k=\sum\limits_{i\otimes j=k}A_i*B_j \]

然后对于FWT(A):

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

IFWT

现在我们可以在\(O(n\log n)\)时间内求出\(FWT(A\oplus B)\),然后还需要再把它变回去,也就是IFWT。
反着做一遍就行力:
对于or:

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

对于and:

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

对于xor:

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

然后放个码,匹配了一下之前FFTNTT的码风:

inline void FWT_or(int *a,int opt){
    for(int mid=1;mid<lim;mid<<=1)
        for(int j=0;j<lim;j+=(mid<<1))
            for(int k=0;k<mid;k++)
            if(opt==1)a[j+mid+k]+=a[j+k],a[j+mid+k]-=a[j+mid+k]>=mod?mod:0;
            else a[j+mid+k]-=a[j+k],a[j+mid+k]+=a[j+mid+k]<0?mod:0;
}
inline void FWT_and(int *a,int opt){
    for(int mid=1;mid<lim;mid<<=1)
        for(int j=0;j<lim;j+=(mid<<1))
            for(int k=0;k<mid;k++)
            if(opt==1)a[j+k]+=a[j+mid+k],a[j+k]-=a[j+k]>=mod?mod:0;
            else a[j+k]-=a[j+mid+k],a[j+k]+=a[j+k]<0?mod:0;
}
inline void FWT_xor(int *a,int opt){
    for(int mid=1;mid<lim;mid<<=1)
        for(int j=0;j<lim;j+=(mid<<1))
            for(int k=0;k<mid;k++){
                int x=a[j+k],y=a[j+mid+k];
                a[j+k]=(x+y)%mod,a[j+mid+k]=(x-y+mod)%mod;
                if(opt==-1)a[j+k]=1ll*a[j+k]*inv2%mod,a[j+mid+k]=1ll*a[j+mid+k]*inv2%mod;
            }
}

对于子集和可以直接:

inline void FWT(int *a){
    for(int mid=1;mid<lim;mid<<=1)
        for(int j=0;j<lim;j+=(mid<<1))
            for(int k=0;k<mid;k++)
           a[j+mid+k]+=a[j+k],a[j+mid+k]-=a[j+mid+k]>=mod?mod:0;
}
posted @ 2021-12-30 19:58  letitdown  阅读(82)  评论(1编辑  收藏  举报