快速莫比乌斯变换(FMT)&快速莫比乌斯反演(FMI)

9 篇文章 0 订阅
4 篇文章 0 订阅

前言

这好像是一个很巧妙的东西
我在FWT的博客里写到的FWTor和FWTand似乎其实并不是真正的FWT,好像就是FMT
而FWTxor才是真正的FWT
而这里有一个更为本质的FMT板子,分治算法可以去看我FWT的博客学习
另外,似乎这里的“莫比乌斯反演”和数论的“莫比乌斯反演有所不同”
本博客部分内容参考:吕凯风, 《集合幂级数的性质与应用及其快速算法》, 国家集训队2015论文集。

问题

现在已知两个函数 f ( S ) , g ( S ) f(S),g(S) f(S)g(S)
我们要求每个 F ( S ) = ∑ A ⊆ S ∑ B ⊆ S f ( A ) g ( B ) F(S)=\sum_{A\subseteq S}\sum_{B\subseteq S}f(A)g(B) F(S)=ASBSf(A)g(B)

解决

我们发现,我们把 f f f g g g F F F翻转后成为 f ′ f' f g ′ g' g F ′ F' F
可以列出以下式子:
F ′ ( S ) = ∑ A ∩ B = S f ′ ( A ) g ′ ( B ) F'(S)=\sum_{A\cap B=S}f'(A)g'(B) F(S)=AB=Sf(A)g(B)
update2021/11/23:


翻转的含义是集合每个值的取/不取状态取反
式子应该为
F ′ ( S ) = ∑ S ⊆ A ∩ B f ′ ( A ) g ′ ( B ) F'(S)=\sum_{S\subseteq A\cap B}f'(A)g'(B) F(S)=SABf(A)g(B)


然后直接FWTand就好了

性质

由于在FWT的博客中我的证明是直接用定义+分治
所以中间过程并没有很好的解释
我们来看and的FWT定义:
F W T ( A ) = ( ∑ i & 0 = 0 a i , ∑ i & 1 = 1 a i , ∑ i & 2 = 2 a i ⋅ ⋅ ⋅ ∑ i & ( n − 1 ) = ( n − 1 ) a i ) \begin{aligned} FWT(A)=(\sum_{i\&0=0}a_i,\sum_{i\&1=1}a_i,\sum_{i\&2=2}a_i···\sum_{i\&(n-1)=(n-1)}a_i) \end{aligned} FWT(A)=(i&0=0ai,i&1=1ai,i&2=2aii&(n1)=(n1)ai)
我们发现把它当成集合,并且翻转之后
就变成了 F ′ ( S ) = ∑ A ⊆ S f ′ ( A ) F'(S)=\sum_{A\subseteq S}f'(A) F(S)=ASf(A)
于是我们获得了很好的快速求这个式子的做法
设元素个数为 n n n,那么复杂度为 Θ ( 2 n n ) \Theta(2^nn) Θ(2nn),比直接枚举子集的 Θ ( 3 n ) \Theta(3^n) Θ(3n)优了不少(应用例题:PKUWC2018随机游走
其实这个东西有一种更加好写的写法、并且不需要翻转(其实真的只是压了一个循环
贴出代码:

inline void FMT(int*A)
{
    for(rg int i=1;i<1<<n;i<<=1)
    	for(rg int j=0;j<1<<n;j++)
			if(i&j)
				A[j]=(A[j]+A[j^i])%mod;
}

其实
f ( S ) = ∑ T ⊆ S g ( T ) f(S)=\sum_{T\subseteq S}g(T) f(S)=TSg(T)
这个才是真正的快速莫比乌斯变换(FMT)

然后我们回到上面,IFWT()究竟是什么呢?
相当于就是进行反演
g ( S ) = ∑ T ⊆ S ( − 1 ) ∣ S ∣ − ∣ T ∣ f ( T ) g(S)=\sum_{T\subseteq S}(-1)^{|S|-|T|}f(T) g(S)=TS(1)STf(T)
然后这就是快速莫比乌斯反演(FMI)

inline void FMI(int*A)
{
    for(rg int i=1;i<1<<n;i<<=1)
    	for(rg int j=0;j<1<<n;j++)
			if(i&j)
				A[j]=A[j]-A[j^i];
}

整合一下变成

inline void FMT(int*A,const int fla)
{
    for(rg int i=1;i<1<<n;i<<=1)
    	for(rg int j=0;j<1<<n;j++)
			if(i&j)
				A[j]=A[j]+fla*A[j^i];
}

总结

大概这是FWTor/FWTand的本质吧
这里的代码和之前的代码有所不同,但是本质一样,有兴趣可以自行推导一下
另外,根据测试,跑 2 25 2^{25} 225的数据的时候,这里的FMT花的时间大概是FWT里的写法跑的时间的1.2倍,略有点常数,所以还是推荐FWT里的and写法

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值