快速莫比烏斯變換 (Fast Mobius Transform, FMT)


子集反演

莫比烏斯變換

\[f(S)=\sum_{T\subseteq S} g(T) \]

莫比烏斯反演

\[g(S)=\sum_{T\subseteq S}(-1)^{|S|-|T|} f(T) \]

證明:

\[\sum_{i=0}^n(-1)^{i}\binom{n}{i}=[n=0] \]

可得

\[\sum_{T\subseteq S} (-1)^{|T|}=[S=\phi] \]

\[g(S)=\sum_{T\subseteq S} [S-T=\phi] g(T)\\ =\sum_{T\subseteq S}\sum_{P\subseteq S-T} (-1)^{|P|} g(T)\\ =\sum_{P\subseteq S}\sum_{T\subseteq S-P} (-1)^{|P|} g(T)\\ =\sum_{P\subseteq S}(-1)^{|P|}\sum_{T\subseteq S-P} g(T)\\ =\sum_{P\subseteq S}(-1)^{|P|}f(S-P)\\ =\sum_{T\subseteq S} (-1)^{|S|-|T|} f(T) \]

證畢。

合並卷積

定義

\[h(S)=f(S)*g(S)=\sum_{A\subseteq S}\sum_{B\subseteq S} f(A)g(B)[A\cup B=S] \]

\(h\)\(f\)\(g\) 的合並卷積。

\(\hat h(S)\)\(h(S)\) 的莫比烏斯變換,則

\[\hat h(S)=\sum_{T\subseteq S}\sum_{A\subseteq T}\sum_{B\subseteq T} f(A)g(B)[A\cup B=T]\\ =\sum_{A\subseteq S}\sum_{B\subseteq S} f(A)g(B)[A\cup B\subseteq S]\\ =\sum_{A\subseteq S}\sum_{B\subseteq S} f(A)g(B)\\ =\sum_{A\subseteq S}f(A)\sum_{B\subseteq S} g(B)\\ =\hat f(S)\hat g(S) \]

這啟發我們計算 \(f\)\(g\) 的合並卷積時,可以先將 \(f\)\(g\) 分別做莫比烏斯變換,然后相乘,得到 \(h\) 的莫比烏斯變換 \(\hat h\),再對 \(\hat h\) 做莫比烏斯反演,即得到 \(f\)\(g\) 的合並卷積 \(h\)

快速莫比烏斯變換 (Fast Möbius Transform, FMT)

要求

\[\hat f(S)=\sum_{T\subseteq S} f(T) \]

定義 \(\hat f(S,i)=\sum_{T\subseteq S}f(T)[\{i+1,i+2,\dots,n\}\subseteq T]\)
那么有 \(\hat f(S,0)=f(S)\)\(\hat f(S,|S|)=f(\phi)\)
設集合 \(S\cap \{i\}=\phi\)

那么 \(\hat f(S\cup \{i\},i)=\hat f(S,i-1)+\hat f(S\cup\{i\},i-1)\)
因為 \(S\cap \{i\}=\phi\),所以 \(\hat f(S,i)=\hat f(S,i-1)\)
\(\hat f(S,i)\)表示 \(\{i+1,i+2,\dots,n\}\) 一定含於 \(T\),並且一定沒有選 \(i\)
\(\hat f(S\cup\{i\},i-1)\) 表示 \(\{i+1,i+2,\dots,n\}\) 一定含於 \(T\),並且一定選了 \(i\)
那么由加法原理即可知 \(\hat f(S\cup \{i\},i)=\hat f(S,i-1)+\hat f(S\cup\{i\},i-1)\)
那么我們遞推 \(n\) 輪,即可求得 \(\hat f(S)\)
時間復雜度 \(O(n2^n)\)

void FMT(int *f){
    for(int i=0;i<n;++i)
        for(int j=0;j<(1<<n);++j)
            if(j&(1<<i)) f[j]+=f[j^(1<<i)];
}

快速莫比烏斯反演 (IFMT)

跟FMT一樣,不斷遞推,不過變成了減法。

void IFMT(int *f){
    for(int i=0;i<n;++i)
        for(int j=0;j<(1<<n);++j)
            if(j&(1<<i)) f[j]-=f[j^(1<<i)];
}

子集卷積

定義

\[h(S)=f(S)*g(S)=\sum_{A\subseteq S}\sum_{B\subseteq S} f(S)g(S)[A\cup B=S][A\cap B=\phi]\\ =\sum_{T\subseteq S} f(T)g(S-T) \]

\(h\)\(f\)\(g\) 的子集卷積。

因為子集卷積和之前的合並卷積不同,要求 \(A\cup B=S, A\cap B=\phi\),那么設 \(f(i,S)\) 表示集合 \(S\)\(i\) 個元素時的 \(f(S)\),那么只有 \(f(|S|,S)\) 才是正確的。先對 \(f\)\(g\) 做FMT,然后對做完FMT的 \(f(i,S)\)\(g(j,S)\) 進行暴力卷積,有 \(h(i+j,S)=\sum_{i,j} f(i,S)*g(j,S)\)。最后再進行一次 IFMT,即可求出子集卷積。時間復雜度 \(O(n^22^n)\)

Code (洛谷 P6097)

#include <bits/stdc++.h>
using namespace std;

#define RG register int
#define LL long long

template<typename elemType>
inline void Read(elemType &T){
    elemType X=0,w=0; char ch=0;
    while(!isdigit(ch)) {w|=ch=='-';ch=getchar();}
    while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    T=(w?-X:X);
}

#define bitcnt(x) __builtin_popcount(x)
const LL MOD=1000000009LL;
int A[1<<21],B[1<<21];  
int a[21][1<<21],b[21][1<<21],c[21][1<<21];
int n,len;

void FMT(int *f,int n){
    for(RG i=0;i<n;++i)
        for(RG j=0;j<(1<<n);++j)
            if(j&(1<<i)) f[j]=(f[j]+f[j^(1<<i)])%MOD;
}
void IFMT(int *f,int n){
    for(RG i=0;i<n;++i)
        for(RG j=0;j<(1<<n);++j)
            if(j&(1<<i)) f[j]=((f[j]-f[j^(1<<i)])%MOD+MOD)%MOD;
}

void Convolution(int n){
    for(RG x=0;x<=n;++x){
        for(RG i=0;i<=x;++i)
            for(RG s=0;s<(1<<n);++s)
                c[x][s]=(1LL*c[x][s]+1LL*a[i][s]*b[x-i][s]%MOD)%MOD;
        IFMT(c[x],n);
    }
}

int main(){
    Read(n);len=1<<n;
    for(RG i=0;i<len;++i){
        Read(A[i]);
        a[bitcnt(i)][i]=A[i];
    }
    for(RG i=0;i<len;++i){
        Read(B[i]);
        b[bitcnt(i)][i]=B[i];
    }
    for(RG i=0;i<=n;++i){
        FMT(a[i],n);
        FMT(b[i],n);
    }
    Convolution(n);
    for(RG i=0;i<len;++i)
        printf("%d ",c[bitcnt(i)][i]);

    return 0;
}

另一份模板

namespace FMT{
    #define bitcnt(x) __builtin_popcount(x)
    const int MOD=998244353LL;
    const int Base=21;

    inline int mo(int x){
        if(x>=MOD) x-=MOD;
        if(x<0) x+=MOD;
        return x;
    }
    inline int mul(int x,int y){return 1LL*x*y%MOD;}

    void FMT(vector<int> &f,int n=Base){
        int len=1<<n;
        for(RG i=0;i<n;++i)
            for(RG j=0;j<len;++j)
                if(j&(1<<i)) f[j]=mo(f[j]+f[j^(1<<i)]);
    }
    void IFMT(vector<int> &f,int n=Base){
        int len=1<<n;
        for(RG i=0;i<n;++i)
            for(RG j=0;j<len;++j)
                if(j&(1<<i)) f[j]=mo(f[j]-f[j^(1<<i)]);
    }

    vector<int> subset_convolution(vector<int> &A,vector<int> &B,int n=Base){
        int len=1<<n;
        vector<int> H(len);
        vector<vector<int> > sH(n+1,vector<int>(len,0)),sA=sH,sB=sH;
        for(RG s=0;s<len;++s){
            sA[bitcnt(s)][s]=A[s];
            sB[bitcnt(s)][s]=B[s];
        }
        for(RG i=0;i<=n;++i){
            FMT(sA[i],n);
            FMT(sB[i],n);
            for(RG s=0;s<len;++s)
                for(RG j=0;j<=i;++j)
                    sH[i][s]=mo(sH[i][s]+mul(sA[j][s],sB[i-j][s]));
            IFMT(sH[i],n);
        }
        for(RG s=0;s<len;++s)
            H[s]=sH[bitcnt(s)][s];
        return H;
    }
};


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM