快速莫比乌斯变换(FMT)与卷积

快速莫比乌斯变换(FMT)

莫比乌斯变换及反演(子集变换及反演)

设 $ f,g $ 为定义在全集 $ U $ 的任意子集上的函数,如果有莫比乌斯变换

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

那么就有广义莫比乌斯反演(简称莫比乌斯反演)

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

证明

考虑二项式定理推论式:

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

考虑对于大小为 $ n $ 的集合做如上子集操作,有:

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

因此对原等式左侧进行恒等变换,有:

\[\begin{align} g(S)=& \sum\limits_{T \subseteq S}[S \setminus T=\phi]g(T) \\ =&\sum\limits_{T \subseteq S}\sum\limits_{P \subseteq S \setminus T }(-1)^{|P|} g(T)\\ =&\sum\limits_{P \subseteq S}\sum\limits_{T \subseteq S \setminus P}(-1)^{|P|}g(T) \\ =&\sum_{P \subseteq S}(-1)^{|P|}\sum\limits_{T \subseteq S \setminus P}g(T)\\ =&\sum\limits_{P \subseteq S}(-1)^{|P|}f(S \setminus P) \end{align} \]

不妨令 $ T =S \setminus P $ ,显然存在 $ T \subseteq S ,|T|=|S|-|P| $ 。对上式做等效变换得:

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

证毕。

合并卷积

我们定义定义域在集合 $ S $ 的全体子集上的函数 $ h(S),f(S),g(S) $ ,若称 $ h(S) $ 为 $ f(S),g(S) $ 的合并卷积,则有:

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

不妨设 $ \hat{h}(S) $ 为 $ h(S) $ 的莫比乌斯变换,则有:

\[\begin{align} \hat{h}(S)=&\sum\limits_{T \subseteq S}h(T) \\ =&\sum\limits_{T \subseteq S}\sum\limits_{A \subseteq T}\sum\limits_{B \subseteq T}f(A)g(B)[A \cup B=T]\\ =&\sum\limits_{A \subseteq S}\sum\limits_{B \subseteq S}f(A)g(B)[A \cup B \subseteq S]\\ =&\sum\limits_{A \subseteq S}\sum\limits_{B \subseteq S}f(A)g(B)\\ =&\sum\limits_{A \subseteq S}f(A)\sum\limits_{B \subseteq S}g(B)\\ =&\hat{f}(S)\hat{g}(S) \end{align} \]

上述推导最后的结果启发我们在对 $ f,g $ 进行合并卷积的时候,可以先将两者进行莫比乌斯变换,相乘之后得到目标函数 $ h $ 的莫比乌斯变换 $ \hat{h} $ ,再对 $ \hat{h} $ 做莫比乌斯反演,即可以得到合并卷积结果 $ h $ 。

快速莫比乌斯变换(Fast Möbius Transform , FMT)

现在我们聚焦于如何快速的计算一个定义域为集合 $ S $ 的函数 $ f(S) $ 的莫比乌斯变换 $ \hat{f}(S) $ ,即:

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

我们将集合 $ S $ 中的元素依次编号为 $ 1 $ 至 $ n $ ,方便用二进制表示子集状态。

定义 $ \hat{f}(S,i)=\sum\limits_{T \subseteq S}f(T)[ {i+1,i+2,\ldots,n}\subseteq T] $ 表示状态为集合 $ {i+1,i+2,\dots,n } $ 一定含于 $ T $ 且一定没有选择 $ i $ ,而 $ \hat{f}(S \cup {i},i-1) $表示 $ {i+1,i+2,\ldots,n} $ 一定含于 $ T $ 并且一定选了 $ i $。显然有 $ \hat{f}(S,0)=f(S),\hat{f}(S,|S|)=f(\phi) $ ,并且有转移方程:

\[\hat{f}(S \cup \{i\},i)=\hat{f}(S \cup \{i\},i-1)+\hat{f}(S,i-1) \]

其实就是高维前缀和,时间复杂度为 $ O(n\times2^n) $。

至于逆变换,只需要将加号变为减号即可。

void FMT(int *f,int type)//莫比乌斯变换type=1,莫比乌斯反演type=-1
{
    for(int i=0;i<n;++i)
        for(int s=0;s<(1<<n);++s)
            if(s&(1<<i)) f[s]+=type*f[s^(1<<i)];
}

子集卷积

题目:[P6097 【模板】子集卷积 - 洛谷](https://www.luogu.com.cn/problem/P6097)

题意:

给定 $ n $ ,以及给定两个长度为 $ 2^n $ 的序列 $ a_0,a_1,\ldots,a_{2^n-1} $ 和 $ b_0,b_1,\ldots,b_{2^n-1} $ ,求出两者的子集卷积结果 $ c_0,c_1,\ldots,c_{2^n-1} $ ,其中:

\[c_k=\sum\limits_{i|j=k,i\&j=0}a_ib_j \]

我们定义定义域在集合 $ S $ 的全体子集上的函数 $ h(S),f(S),g(S) $ ,若称 $ h(S) $ 为 $ f(S),g(S) $ 的子集卷积,则有:

\[\begin{align} h(S)=f(S)*g(S)=&\sum\limits_{A \subseteq S}\sum\limits_{B \subseteq S}f(A)g(B)[A \cup B=S][A\cap B=\phi]\\ =&\sum\limits_{T \subseteq S}f(T)g(S \setminus T) \end{align} \]

对比之前的合并卷积,发现子集卷积多了一个 $ A \cap B=\phi $ 的要求。

我们设 $ p(x) $ 为 $ x $ 的 $ popcount $(即 $ 1 $ 的个数),那么:

\[A \cup B=S,A \cap B=\phi \Longleftrightarrow A \cup B=S,|A|+|B|=|S| \]

我们用状压状态来代表一个集合,不妨令 $ A $ 的状压状态为 $ i $ ,$ B $ 的状压状态为 $ j $ ,全集为 $ s $。那么则有:

\[i|j=s,i\&j=0 \Longleftrightarrow i|j=s,p(i)+p(j)=p(s) \]

有转移:

\[h(S)=\sum\limits_{i|j=s,p(i)+p(j)=p(s)}f(i)g(j) \]

将状态拓展到二维,设 $ h_{x,s} $ 为状压状态为 $ s $ ,其中有 $ x $ 个元素,显然只有 $ h_{p(s),s} $ 时状态才有意义,那么可以得到卷积:

\[h_{x,s}=\sum\limits_{i|j=s,p(i)+p(j)=x}f(i)g(j)[p(s)=x] \]

同时我们也要将 $ f(i),g(j) $ 拓展到二维,不妨令:

\[f_{x,i}=f(i)[p(i)=x],g_{x,j}=g(j)[p(j)=x] \]

那么可以得到卷积:

\[h_{x,s}=\sum\limits_{i|j=s,p(i)+p(j)=x}f_{p(i),i}g_{p(j),j} \]

我们暴力枚举 $ x,p(i) $ ,这样就可以唯一确定 $ p(j) $ ,然后我们再正常进行点乘操作,最后进行一次莫比乌斯反演即可,时间复杂度 $ O(n^2 \times 2^n) $ 。

#include<bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;

#define bitcnt(x) __builtin_popcount(x)
const int mod=1e9+9;
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(int i=0;i<n;++i)
        for(int 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(int i=0;i<n;++i)
        for(int 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(int x=0;x<=n;++x)
	{
        for(int i=0;i<=x;++i)
            for(int 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);
    }
}

signed main()
{
	ios::sync_with_stdio(false);
	cin.tie(NULL);
	cout.tie(NULL);
	
	cin>>n;
	len=1<<n;
	for(int i=0;i<len;i++) 
	{
		cin>>A[i];
		a[bitcnt(i)][i]=A[i];
	}
	for(int i=0;i<len;i++) 
	{
		cin>>B[i];
		b[bitcnt(i)][i]=B[i];
	}
	Convolution(n);
	for(int i=0;i<len;i++) cout<<c[bitcnt(i)][i]<<' ';
}

整理的板子:

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(register int i=0;i<n;i++)
            for(register int j=0;j<(1<<n);j++)
                if((j>>i)&1) f[j]=mo(f[j]+f[j^(1<<i)]);
    }
    void IFMT(vector<int>& f,int n=Base)
    {
        int len=1<<n;
        for(register int i=0;i<n;i++)
            for(register int j=0;j<(1<<n);j++)
                if((j>>i)&1) 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(register int s=0;s<len;++s)
        {
            sA[bitcnt(s)][s]=A[s];
            sB[bitcnt(s)][s]=B[s];
        }
        for(register int i=0;i<=n;++i)
        {
            FMT(sA[i],n);
            FMT(sB[i],n);
            for(register int s=0;s<len;++s)
                for(register int 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(register int s=0;s<len;++s)
            H[s]=sH[bitcnt(s)][s];
        return H;
    }
}

参考资料:

快速莫比乌斯变换 (Fast Mobius Transform, FMT) - AE酱 - 博客园

FMT(快速莫比乌斯变换) - 知乎

posted on 2025-08-02 22:06  Linear_L  阅读(53)  评论(0)    收藏  举报