小 Tips:在计算机语言中 \(\cap\) = & / and, \(\cup\) = | / or

First. 定义

定义长度为 \(2^n\) 的序列的 and 卷积 \(A = B * C\) 为 \(A_i=\sum_{j \cap k = i}{B_j \times C_k}\)

考虑快速计算

Second. 变换

定义长度为 \(2^n\) 的序列的 Zeta 变换

\[\hat A_i = \sum_{j \subseteq i}{A_j}
\]

即子集和

它具有一下性质:

\[\hat B_i \times \hat C_i
= \sum_{j \subseteq i} B_j \times \sum_{k \subseteq i} C_k
= \sum_{p \subseteq i} \sum_{j \cap k = p} B_j \times C_k
= \sum_{p \subseteq i} A_p = \hat A_i
\]

相当于 FFT 中的点值表示法,用以加速卷积过程

Third. 快速变换

暴力求解 \(\hat A\) 最优时间复杂度为 \(3^n\),考虑加速

考虑 子集DP ,有一篇很好的博客[1],这里大概讲解一下。

其实 \(\hat A\) 本质上是一个高维( \(n\) 维)前缀和

如果我们要求二维前缀和,显然可以通过一下代码实现:

// 1st
for(int i=1; i<=n; ++i)
for(int j=1; j<=m; ++j)
a[i][j]+=a[i-1][j];
// 2nd
for(int i=1; i<=n; ++i)
for(int j=1; j<=n; ++j)
a[i][j]+=a[i][j-1];

我们发现 1st 完成后 a[i][j] 表示的是 \(\sum_{k \le i} a_{k,j}\),即 \((i,j)\) 上方的元素和

那么 2nd 便是将 \((i,j)\) 左边操作后的 \(\sum_{k \le j} a_{i,k}\) 累加到 a[i][j] 中,即完成二维前缀和


下面拓展到三维前缀和

// 1st
for(int i=1; i<=n; ++i)
for(int j=1; j<=n; ++j)
for(int k=1; k<=n; ++k)
a[i][j][k]+=a[i-1][j][k];
// 2nd
for(int i=1; i<=n; ++i)
for(int j=1; j<=n; ++j)
for(int k=1; k<=n; ++k)
a[i][j][k]+=a[i][j-1][k];
// 3rd
for(int i=1; i<=n; ++i)
for(int j=1; j<=n; ++j)
for(int k=1; k<=n; ++k)
a[i][j][k]+=a[i][j][k-1];

类似地,1st,2nd 中处理除了第 k 平面中的二维前缀和,3rd 在立体空间中把他们加起来,成为三维前缀和


回到 Zeta 变换

\[\hat A_i = \sum_{j \subseteq i}{A_j}
\]

如果我们用二进制 \((x_{n-1}x_{n-2}x_{n-3}\ ...\ x_2x_1x_0)_2\) 表示集合 \(i\),二进制 \((y_{n-1}y_{n-2}y_{n-3}\ ...\ y_2y_1y_0)_2\) 表示集合 \(j\)

那么 \(\hat A_i\) 可以被视为 \(n\) 维前缀和,即

\[\hat A_i = \sum_{y_{n-1}\le x_{n-1},y_{n-2}\le x_{n-2},\ ...,\ y_1\le x_1,y_0\le x_0} A_j
\]

当然,下标都为 0/1

因此,我们有如下 Code:

for(int i=0; i<n; ++i)
for(int j=0; j<(1<<n); ++j)
if(j&(1<<i))
a[j]+=a[j^(1<<i)];

以上 Code 的 naive 形式为:

for(int i1=0; i1<2; ++i1) for(int i2=0; i2<2; ++i2) ... for(int in=0; in<2; ++in) if(i1>0) a[i1][i2][...][in]+=a[i1-1][i2][...][in];
for(int i1=0; i1<2; ++i1) for(int i2=0; i2<2; ++i2) ... for(int in=0; in<2; ++in) if(i2>0) a[i1][i2][...][in]+=a[i1][i2-2][...][in];
...
for(int i1=0; i1<2; ++i1) for(int i2=0; i2<2; ++i2) ... for(int in=0; in<2; ++in) if(in>0) a[i1][i2][...][in]+=a[i1][i2][...][in-1];

不要质疑我代码编译不通过

因此,我们用 \(O(n2^n)\) 的时间复杂度解决了 Zeta 变换

Fourth. 逆变换

warning:此处不是 莫比乌斯反演

众所周知,前缀和的逆运算即为差分

我们发现,只需要先将最后一维差分,即可将序列处理为 \(n-1\) 维前缀和

for(int i1=0; i1<2; ++i1) for(int i2=0; i2<2; ++i2) ... for(int in=0; in<2; ++in) if(in>0) a[i1][i2][...][in]-=a[i1][i2][...][in-1];
...
for(int i1=0; i1<2; ++i1) for(int i2=0; i2<2; ++i2) ... for(int in=0; in<2; ++in) if(i2>0) a[i1][i2][...][in]-=a[i1][i2-2][...][in];
for(int i1=0; i1<2; ++i1) for(int i2=0; i2<2; ++i2) ... for(int in=0; in<2; ++in) if(i1>0) a[i1][i2][...][in]-=a[i1-1][i2][...][in];

但实际上因为前缀和都是无序的,因此我们直接正着做就可以啦

只需要把正变换的 += 改为 -= 就可以了

Fifth. 扩展

有时候,题目给的不是 \(\cap\) ,而是 \(\cup\) 怎么办?

那我们重定义 Zeta 变换 为:

\[\hat A_i = \sum_{i \supseteq j} A_j
\]

再推一下式子:

\[\hat B_i \times \hat C_i
=\sum_{i\supseteq j} B_j \times \sum_{i\supseteq k} C_k
=\sum_{i\supseteq j,i\supseteq k} B_j \times C_k
=\sum_{i\supseteq p} \sum_{j \cup k=p} B_j \times C_k
=\sum_{i\supseteq p} A_p
=\hat A_i
\]

变换即超集和,高维后缀和

求法也很简单,只用将源代码中的 if(j&(1<<i)) 该为 if(!(j&(1<<i))) 即可


是 \(\oplus\) 怎么办?

快去学 FWT 吧

Last. 例题

再送你一个并/交集的小口诀:下并或,上交与


  1. 高维前缀和总结(sosdp) - heyuhhh - 博客园 (cnblogs.com)

Fast Möbius Transform 学习笔记 | FMT的更多相关文章

  1. ios 控件代码transform学习笔记

    1.图片设置(平移,缩放,旋转) 创建一个transform属性 //按钮点击时,只能执行一次向上旋转 //派 M_PI_4 45度旋转 . CGAffineTransform transforms= ...

  2. css笔记 - transform学习笔记(二)

    transform转换 CSS transform 属于2D/3D上的转换.变形效果.他不是一个动画,他就是变形.比如正方形变平行四边形,再变圆形.都是形状变成另一个形状. 但是如果配合上transi ...

  3. FMT/FWT学习笔记

    目录 FMT/FWT学习笔记 FMT 快速莫比乌斯变换 OR卷积 AND卷积 快速沃尔什变换(FWT/XOR卷积) FMT/FWT学习笔记 FMT/FWT是算法竞赛中求or/and/xor卷积的算法, ...

  4. 「学习笔记」Fast Fourier Transform

    前言 快速傅里叶变换(\(\text{Fast Fourier Transform,FFT}\) )是一种能在\(O(n \log n)\)的时间内完成多项式乘法的算法,在\(OI\)中的应用很多,是 ...

  5. [原创]java WEB学习笔记52:国际化 fmt 标签,国际化的总结

    本博客为原创:综合 尚硅谷(http://www.atguigu.com)的系统教程(深表感谢)和 网络上的现有资源(博客,文档,图书等),资源的出处我会标明 本博客的目的:①总结自己的学习过程,相当 ...

  6. [学习笔记&教程] 信号, 集合, 多项式, 以及各种卷积性变换 (FFT,NTT,FWT,FMT)

    目录 信号, 集合, 多项式, 以及卷积性变换 卷积 卷积性变换 傅里叶变换与信号 引入: 信号分析 变换的基础: 复数 傅里叶变换 离散傅里叶变换 FFT 与多项式 \(n\) 次单位复根 消去引理 ...

  7. [学习笔记] 多项式与快速傅里叶变换(FFT)基础

    引入 可能有不少OIer都知道FFT这个神奇的算法, 通过一系列玄学的变化就可以在 $O(nlog(n))$ 的总时间复杂度内计算出两个向量的卷积, 而代码量却非常小. 博主一年半前曾经因COGS的一 ...

  8. Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十八章:立方体贴图

    原文:Introduction to 3D Game Programming with DirectX 12 学习笔记之 --- 第十八章:立方体贴图 代码工程地址: https://github.c ...

  9. 快速傅里叶变换(FFT)学习笔记(其一)

    再探快速傅里叶变换(FFT)学习笔记(其一) 目录 再探快速傅里叶变换(FFT)学习笔记(其一) 写在前面 为什么写这篇博客 一些约定 前置知识 多项式卷积 多项式的系数表达式和点值表达式 单位根及其 ...

  10. 【OI向】快速傅里叶变换(Fast Fourier Transform)

    [OI向]快速傅里叶变换(Fast Fourier Transform) FFT的作用 ​ 在学习一项算法之前,我们总该关心这个算法究竟是为了干什么. ​ (以下应用只针对OI) ​ 一句话:求多项式 ...

随机推荐

  1. hadoop集群启动脚本文件myhadoop.sh

    #!/bin/bash if [ $# -lt 1 ] then echo "No Args Input..." exit ; fi case $1 in "start& ...

  2. 【Java】归并排序

    代码: 1 public static void mergeSort(int[] arr) { 2 if (arr == null || arr.length < 2) { 3 return; ...

  3. 冒泡排序【Java】

    1 public class Paixu { 2 public static void main(String args[]) { 3 int myNum[] = {2,6,4,1,5}; 4 //从 ...

  4. ASCII编码的全面介绍

    1. ASCII编码的定义和历史 ASCII(American Standard Code for Information Interchange)是一种用于将文本字符转换为数字编码的标准,最初由美国 ...

  5. 实际项目中如何使用Git做分支管理

    前言 Git是一种强大的分布式版本控制系统,在实际项目开发中使用Git进行分支管理是非常常见的做法,因为它可以帮助团队高效的协作和管理项目的不同版本,今天我们来讲讲在实际项目中最常用的Git分支管理策 ...

  6. #最大公约数#CF346A Alice and Bob

    题目传送门 CF346A 分析 可以发现其所能表示的数就是能被最大公约数整除的数,且这些数不能超过最大值, 于是判断一下取数的奇偶性即可 代码 #include <cstdio> #inc ...

  7. #树形dp,二次扫描换根法#JZOJ 3501 消息传递 with others

    目录 JZOJ 3501 消息传递 题目 分析 代码 简单写就能跳过之题目 JZOJ 3500 物语 题目 分析 代码 JZOJ 3757 洛谷 2354 [NOI 2014] 随机数产生器 题目 分 ...

  8. 【原创】win11完美搭建macos13实现IOS自动化测试环境

    虚拟机完美搭建IOS自动化测试环境 一.win系统 1.1 安装虚拟机VM16 如果是macos系统请跳过 详细安装请看压缩包,私信可以提供安装包 1.2 VM解锁macOS 使用的是unlocker ...

  9. 2024-04-13:用go语言,给定一个整数数组 `nums`, 请编写一个函数,返回一个新的数组 `counts`。 满足以下条件:对于每个 `nums[i]`, `counts[i]` 表示在

    2024-04-13:用go语言,给定一个整数数组 nums, 请编写一个函数,返回一个新的数组 counts. 满足以下条件:对于每个 nums[i], counts[i] 表示在 nums[i] ...

  10. SVM三则

    硬间隔SVM SVM被提出来, 解决模式识别中, 数据的分类问题,属于有监督算法中的一种, 如上图所示, 于其他的线性回归方式不同, SVM企图去寻找一个最完美的超平面, 因为能正确分类样本的线, 它 ...