快速莫比乌斯变换 FMT

莫比乌斯变换

一点小小的组合数学:

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

左式为莫比乌斯变换,右侧为逆变换即为莫比乌斯反演。

直接做是 \(O(3^n)\) 的,真是太不牛了!

快速莫比乌斯变换

先考虑子集 FMT。

不难想到 SOSDP 于是就做完了((

然后考虑逆变换 IFMT,同理,把加法换成减法即可。

超集 FMT 也是同理的。就直接放板子了。逆变换时,\(x\) 传入 \(-1\)

inline vec<mint> subFMT(vec<mint> v,mint x=1){
	int n=__lg(v.size());
	repl(i,0,n)repl(s,0,1<<n)if(s>>i&1)v[s]+=v[s^1<<i]*x;
	return v;
}
inline vec<mint> supFMT(vec<mint> v,mint x=1){
	int n=__lg(v.size());
	repl(i,0,n)repl(s,0,1<<n)if(s>>i&1)v[s^1<<i]+=v[s]*x;
	return v;
}

或卷积

求:

\[h(S)=\sum_{T\cup R=S}f(T)g(R) \]

有:

\[\mathrm{FMT}(h)=\mathrm{FMT}(f)\cdot\mathrm{FMT}(g) \]

证明带入一下即可:

\[\begin{aligned} \left[x\right]\mathrm{FMT}(h)&=\sum_{S\sube x}h(S)\\ &=\sum_{S\sube x}\sum_{T\cup R=S}f(T)g(R)\\ &=\sum_{T\cup R\sube x}f(T)g(R)\\ &=\sum_{T\sube x}f(T)\cdot\sum_{R\sube x}g(R)\\ &=[x]\mathrm{FMT}(f)\cdot[x]\mathrm{FMT}(g) \end{aligned} \]

子集卷积

\[h(S)=\sum_{T\sube S}f(T)g(S\setminus T) \]

我们将 \(f,g,h\) 均扩展到二维,\(f(x,S)\) 表示 \(|S|=x\)\(S\) 答案,\(g,h\) 同理。

那么有:

\[h(|S|,S)=\sum_{T\cup R=S,|T|+|R|=|S|}f(|T|,T)g(|R|,R) \]

不难发现是一个或卷积的形式,有:

\[\mathrm{FMT}(h(x))=\sum_{i=0}^x\mathrm{FMT}(f(i))\cdot\mathrm{FMT}(g(x-i)) \]

硬卷就行,\(O(n^22^n)\)

习题

P1539 [TJOI2011] 01矩阵

并不必需 FMT,不过可以用。

值得一提的是,如果只用了 FMT 求子集和或者超集和的话,实际上就是 SOSDP 换了个名字……

对于本题,首先一侧长度在 \(\sqrt n\) 级别为 \(15\) 可以状压,于是状压 DP,行内限制可以直接检查,主要是行间限制,暂时翻转当前行各位的值之后就是一个子集和形式,直接 FMT 即可。

code
const int N=15;

int n,m;
int lm[N*N][N*N];
vec<mint> f;

inline vec<mint> subFMT(vec<mint> v,mint x=1){
	int n=__lg(v.size());
	repl(i,0,n)repl(s,0,1<<n)if(s>>i&1)v[s]+=v[s^1<<i]*x;
	return v;
}
inline vec<mint> supFMT(vec<mint> v,mint x=1){
	int n=__lg(v.size());
	repl(i,0,n)repl(s,0,1<<n)if(s>>i&1)v[s^1<<i]+=v[s]*x;
	return v;
}

inline void Main(){
	cin>>n>>m;
	repl(i,0,n)repl(j,0,m){
		char ch;cin>>ch;
		if(ch=='.')lm[i][j]=-1;
		else lm[i][j]=ch-'0';
	}
	if(n>m){
		repl(i,0,n)repl(j,0,m)if(i>j)swap(lm[i][j],lm[j][i]);
		swap(n,m);
	}
	f.resize(1<<n);f[0]=1;
	repl(i,0,m){
		f=subFMT(f);
		repl(s,0,1<<n-1)swap(f[s],f[s^(1<<n)-1]);
		repl(s,0,1<<n){
			repl(i,1,n)if(s>>i&s>>i-1&1)f[s]=0;
			repl(j,0,n)if(~lm[j][i]&&(lm[j][i]^s>>j&1))f[s]=0;
		}
	}
	mint ans;repl(s,0,1<<n)ans+=f[s];put(ans);
}
posted @ 2025-12-21 13:37  LastKismet  阅读(2)  评论(0)    收藏  举报