FMT 与 子集(逆)卷积

本文参考了 Dance of Faith 大佬的博客

我们定义集合并卷积

hS=LSRS[LR=S]fLgR

最暴力的时候只能 O(4n) 完成,进行 一些优化 可以在 O(3n) 内完成,当然我们可以在 O(n2n) 利用 FMT 或者 FWT 内快速处理。

FMT 原理更好理解,就介绍此种方式。

具体来说,类似与 FFT 我们把 f,g 求点值,然后点值相乘后再插值变化回去。因为要快速实现这个过程,我们可以考虑利用 快速莫比乌斯变换快速莫比乌斯反演 实现。

定义

定义 f 的莫比乌斯变换 f^ ,满足 fS^=TSfT 。(也就是 f^ 是原来函数 f 的子集和)

定义 f^ 的莫比乌斯反演 f ,利用容斥原理可以得到 fS=TS(1)|S||T|fT

考虑为什么这个形式满足集合并卷积。

hS=LSRS[LR=S]fLgR

左右同时做莫比乌斯变换。

hS^=TSLTRT[LR=T]fLgR=LSRS[LRS]fLgR

由于 [LRS]=[LS][RS] ,也就有

hS^=LSRSfLgR=(LSfL)(LSgR)=fL^gR^

证毕。

快速变换与反演

原理讲解

上面那两个集合和我们暴力做是 O(3n) 的,可以进行优化。

考虑按 集合大小 分层递推。

fS^(i)TS[(ST){0,1,2,...,i}]fT ,有 f^S(0)=fS

那么对于不包含 {i} 的集合 S ,满足 fS^(i)=fS^(i1) ,那么它的贡献就是

f^S{i}(i)=f^S(i1)+f^S{i}(i1)

这样,递推 n 轮后 f^S(n) 就包含所有情况,即为所求变换。

对于莫比乌斯反演的话,同样递推,不断减掉就行了。

代码实现

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

子集卷积

原理讲解

我们定义 fg 的子集卷积 fg=h

hS=LSRS[LR=S,LR=]fLgR

其实就是

hS=TSfTgST

刚刚讲的子集并卷积为何不行呢?因为有 [LR=] 的这个限制。

如何去掉这个限制呢,我们多记一维集合大小,也就是 fi,S 表示有 i 个元素,集合表示为 S

显然当且仅当 i=|S| 时是正确的,我们先做 FMT

所以递推的时候就是 hi+j,S=i,jfi,Sgj,S ,其实是个多项式乘法。

由于前面对于 n 个函数进行 FMT 需要 O(n22n) 的复杂度。

这里 FFT 也优化不了复杂度(而且由于常数会慢很多),那么直接暴力卷积就好了。

代码实现

for (int i = 0; i <= n; ++ i) { for (int j = 0; i + j <= n; ++ j) for (int S = 0; S < (1 << n); ++ S) h[i + j][S] += f[i][S] * g[j][S]; }

最后我们要求 S 的子集卷积的结果,直接用 hbitcount(S),S IFMT 的。

子集逆卷积

原理讲解

我们有时候需要做子集卷积意义下的除法或者相关运算。

比如对于两个函数 fg=h ,我们已知 g,h 要求 f

那么就是 f=hg1 。其实就是要求 g1 在子集卷积意义下的结果。

同样我们只需要考虑 FMT 之后的结果。

由于对于每一位我们做的是多项式下的乘法。其实就是对于每一位求的 g1 就是多项式求逆后的结果。

同样对于别的运算也是多项式后的结果。

但是写那个 O(nlogn) 的倍增多项式求逆显然十分地麻烦,可以考虑 O(n2) 递推。

g1=t 假设我们求出 t0,1,,i1 ,要求 ti(t0=g01)

我们可以把 gi 减去 tgi1 项做卷积后的第 i 项的值,就是所求的 ti

这样就可以解决啦qwq

代码

inline void Inv(int *f) { tmp[0] = fpm(f[0], Mod - 2); for (int i = 0; i <= n; ++ i) { inv[i] = tmp[i]; for (int j = 0; i + j <= n; ++ j) tmp[i + j] -= inv[i] * f[j]; } }

__EOF__

本文作者zjp_shadow
本文链接https://www.cnblogs.com/zjp-shadow/p/10263392.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   zjp_shadow  阅读(1836)  评论(0编辑  收藏  举报
编辑推荐:
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
阅读排行:
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
· 为什么 退出登录 或 修改密码 无法使 token 失效
点击右上角即可分享
微信分享提示