码迷,mamicode.com
首页 > 其他好文 > 详细

FWT

时间:2019-12-30 19:00:50      阅读:102      评论:0      收藏:0      [点我收藏+]

标签:问题   log   har   void   std   ref   its   子集   typedef   

一、处理的问题:

给出两个序列\(A,B\),求出序列\(C\),其中\(C_i=\sum\limits_{j\oplus k=i}A_j*B_k\),其中\(\oplus\)是一种运算。

二、举例

我们运用\(FFT\)的思想,考虑先对\(A,B\)构造一个序列\(FWT(A)\)\(FWT(B)\),满足\(FWT(C)_i=FWT(A)_i*FWT(B)_i\),之后再从\(FWT(C)\)转为\(C\)

拿或运算举例:

如果有\(k=i\mid j\),那么\(i,j\)必定是\(k\)的子集。

我们首先构造\(FWT(A)_i=A'_i=\sum\limits_{i=i|j}A_j\),表示\(j\)\(i\)的子集。

那么就会有:
\(C'_i=\sum\limits_{i=i|(j|k)}C_{j|k}=\sum\limits_{i=i|j}A_j*\sum\limits_{i=i|k}B_k=A'_i*B'_i\)
即:
\(FWT(C)_i=FWT(A)_i*FWT(B)_i\)

现在考虑怎么求\(FWT(A)\)

暴力显然是\(O(n^2)\)的(对每个\(i\)枚举\(j\)),我们考虑分治。

这时我们将\(A\)一分为二,我们令\(A_1\)表示序列\(A\)的前半段,\(A_2\)表示\(A\)的后半段。

这时我们发现:
\(FWT(A)=merge(FWT(A_1),FWT(A_1)+FWT(A_2))\)
其中\(merge\)表示将两个序列前后拼接在一起,\(+\)表示每一位相加。

因为对于\(FWT(A)\)的前半段,因为当前二进制最高位为\(0\),所以它就等于\(FWT(A_1)\)

而对于\(FWT(A)\)的后半段,首先它肯定有\(FWT(A_2)\),我们考虑\(A_1\)中的元素对\(FWT(A)\)后半段的贡献。

我们设\(len(A_1)=len(A_2)=l\)

那么对于\(i<l\),\(i\)\(i+l\)只在最高位上差了\(1\),而我们已经最高位为\(1\)的都统计进了\(FWT(A_2)\),这时\(FWT(A)_i\)存的就是\(FWT(A)_{i+l}\)缺少的所有\(A_j\)

于是我们可以递归分治\(O(nlogn)\)来进行\(FWT\)

我们求出\(FWT(C)\)之后还要进行逆变换,于是我们考虑\(IFWT\)怎么做。

其实\(IFWT\)很简单,我们只要按照刚才\(FWT\)时的过程逆着来一遍即可。

\(IFWT(C)=merge(IFWT(C_1),IFWT(C_2)-IFWT(C_1))\)

三、推广

更广泛地说,我们定义\(\oplus\)\(FWT\)为:
\(A'=\{\sum\limits_{i\oplus j=0}A_i*B_j,\sum\limits_{i\oplus j=1}A_i*B_j,...,\sum\limits_{i\oplus j=n-1}A_i*B_j\}\)

现在给出其它运算的\(FWT\)求法:

与或运算相同,我们可以推出与运算的求法:
\(FWT(A)=merge(FWT(A_1)+FWT(A_2),FWT(A_2))\)
\(IFWT(A)=merge(IFWT(A_1)-IFWT(A_2),IFWT(A_2))\)

异或运算:
直接抄结论(不会证):
\(FWT(A)=(FWT(A_1)+FWT(A_2),FWT(A_1)-FWT(A_2))\)
\(IFWT(A)=(\frac{FWT(A_1)+FWT(A_2)}{2},\frac{FWT(A_1)-FWT(A_2)}{2})\)

同或(我今天才知道有这么个东西):
\(FWT(A)=(FWT(A_2)-FWT(A_1),FWT(A_2)+FWT(A_1))\)
\(IFWT(A)=(\frac{FWT(A_2)-FWT(A_1)}{2},\frac{FWT(A_2)+FWT(A_1)}{2})\)

模板题

code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=(1<<17)+10;
const ll mod=998244353;
const ll inv2=mod+1>>1;
int n,m;
ll A[maxn],B[maxn],a[maxn],b[maxn],c[maxn];
inline ll read()
{
    char c=getchar();ll res=0,f=1;
    while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
    while(c>='0'&&c<='9')res=res*10+c-'0',c=getchar();
    return res*f;
}
void fwt_or(ll* a,int op)
{
    for(int mid=1;mid<n;mid<<=1)
        for(int i=0,l=mid<<1;i<n;i+=l)
            for(int j=0;j<mid;j++)
                if(!op)a[i+mid+j]=(a[i+j]+a[i+mid+j])%mod;
                else a[i+mid+j]=((a[i+mid+j]-a[i+j])%mod+mod)%mod;
}
void fwt_and(ll* a,int op)
{
    for(int mid=1;mid<n;mid<<=1)
        for(int i=0,l=mid<<1;i<n;i+=l)
            for(int j=0;j<mid;j++)
                if(!op)a[i+j]=(a[i+j]+a[i+mid+j])%mod;
                else a[i+j]=((a[i+j]-a[i+mid+j])%mod+mod)%mod;
}
void fwt_xor(ll* a,int op)
{
    for(int mid=1;mid<n;mid<<=1)
        for(int i=0,l=mid<<1;i<n;i+=l)
            for(int j=0;j<mid;j++)
            {
                ll x=a[i+j],y=a[i+mid+j];
                if(!op)a[i+j]=(x+y)%mod,a[i+mid+j]=((x-y)%mod+mod)%mod;
                else a[i+j]=(x+y)%mod*inv2%mod,a[i+mid+j]=((x-y)%mod+mod)%mod*inv2%mod;
            }
}
int main()
{
    //freopen("test.in","r",stdin);
    //freopen("test.out","w",stdout);
    m=read();n=1<<m;
    for(int i=0;i<n;i++)A[i]=a[i]=read()%mod;
    for(int i=0;i<n;i++)B[i]=b[i]=read()%mod;
    fwt_or(a,0);fwt_or(b,0);
    for(int i=0;i<n;i++)c[i]=a[i]*b[i]%mod;
    fwt_or(c,1);
    for(int i=0;i<n;i++)printf("%lld ",c[i]);
    puts("");
    for(int i=0;i<n;i++)a[i]=A[i],b[i]=B[i];
    fwt_and(a,0);fwt_and(b,0);
    for(int i=0;i<n;i++)c[i]=a[i]*b[i]%mod;
    fwt_and(c,1);
    for(int i=0;i<n;i++)printf("%lld ",c[i]);
    puts("");
    for(int i=0;i<n;i++)a[i]=A[i],b[i]=B[i];
    fwt_xor(a,0);fwt_xor(b,0);
    for(int i=0;i<n;i++)c[i]=a[i]*b[i]%mod;
    fwt_xor(c,1);
    for(int i=0;i<n;i++)printf("%lld ",c[i]);
    puts("");
    return 0;
}

FWT

标签:问题   log   har   void   std   ref   its   子集   typedef   

原文地址:https://www.cnblogs.com/nofind/p/12121133.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!