快速莫比乌斯变换

数学公式

  • 记\(S\)为全集,\(T\)为其子集
\[\begin{align}
&zeta变换:F(S)=\sum_{T\subseteq S}f(T)\\ \\
&莫比乌斯反演:f(S)=\sum_{T\subseteq S}(-1)^{|S|-|T|}F(T)
\end{align}
\]
  • \(zeta\)变换与\(sosdp\)中的子集求和、超集求和一致,只不过这里的集合范畴不仅限于二进制集合
  • 莫比乌斯反演的作用就在于将超集和或者子集和反演为原来的函数

代码实现(二进制集合)

\(zeta\)变换(子集和)

伪代码:

for 每一位 bit i:
for 每个 mask:
如果 mask 有第 i 位:
F[mask] += F[mask 去掉第 i 位]

代码:

void zeta(vector<ll> &f, int n) {
for (int i = 0; i < n; i++) { // 枚举每一位
for (int mask = 0; mask < (1 << n); mask++) {
if (mask & (1 << i)) { // 如果第 i 位是 1
f[mask] += f[mask ^ (1 << i)];
}
}
}
}

\(Mobius\)反演

伪代码:

for 每一位 bit i:
for 每个 mask:
如果 mask 有第 i 位:
F[mask] -= F[mask 去掉第 i 位]

代码:

void mobius(vector<ll> &f, int n) {
for (int i = 0; i < n; i++) {
for (int mask = 0; mask < (1 << n); mask++) {
if (mask & (1 << i)) {
f[mask] -= f[mask ^ (1 << i)];
}
}
}
}

数论中的莫比乌斯反演

若有:

\[F(n)=\sum_{d|n}f(d)
\]

其中\(d|n\)表示\(d\)为\(n\)的因数

则有:

\[f(n)=\sum_{d|n}\mu(d)·F\left( \frac{n}{d} \right)
\]

其中\(\mu(d)\)为数论莫比乌斯函数,对应着莫比乌斯反演中的\((-1)^{|S|-|T|}\);\(n\)对应着全集\(S\);\(\frac{n}{d}\)对应着子集\(T\)

莫比乌斯函数的定义:

\[\mu(n)=
\begin{cases}
\begin{align}
&1,&n=1\\ \\
&(-1)^k &n是k个不同质数的乘积\\ \\
&0 &n有平方因子
\end{align}
\end{cases}
\]

基于欧拉筛的\(\mu\)函数代码:

int mu[MX], vis[MX], p[MX], cnt;
void init() {
mu[1] = 1;
rep(i, 2, MX - 1) {
if (!vis[i])p[++cnt] = i, mu[i] = -1;
for (int j = 1; i * p[j] < MX; j++) {
vis[i * p[j]] = 1;
if (i % p[j] == 0)break;
mu[i * p[j]] = -mu[i];
}
}
}

例题:树上lcm

思路

设\(f(x)\)为路径\(lcm\)为\(x\)的简单路径数

由于涉及因数与求和,联想到莫比乌斯反演

\[设f(x)=\sum_{d|x}\mu(d)g\left( \frac{x}{d} \right)
\]

由莫比乌斯反演:

\[g(n)=\sum_{d|n}f(d)
\]

因此得到\(g(n)\)的定义:路径\(lcm\)为\(n\)的因数的简单路径数

因此可以先将整棵树上不是\(x\)的因数的节点删去,此时每个连通块内的任意两点构成的简单路径的\(lcm\)都是\(x\)的因数!

dfs染色统计每个连通块的大小,计算有多少条简单路径即可

代码实现

#include<iostream>
#include<cstdio>
#include<vector>
#include<algorithm>
#include<queue>
#include<cmath>
#include<unordered_map>
#include<set>
using namespace std;
using ll = long long;
#define rep(i, a, b) for(ll i = (a); i <= (b); i ++)
#define per(i, a, b) for(ll i = (a); i >= (b); i --)
//#define see(stl) for(auto&ele:stl)cout<<ele<<" "; cout<<'\n';
#define int ll
const int N = 1e5 + 5;
const int MX = 1e7 + 5;
int n, x;
struct node {
vector<int>e;
int val, tag, siz;
}a[N]; ll gcd(ll a, ll b) {
if (b == 0)return a;
return gcd(b, a % b);
}
ll lcm(ll a, ll b) {
return a * b / gcd(a, b);
} void dfs(int u, int fa, int fac) {
if (lcm(a[u].val, fac) > fac)a[u].tag = -1;
else a[u].tag = 0;
for (auto& son : a[u].e) {
if (son == fa)continue;
dfs(son, u, fac);
}
} void dfs2(int u, int fa) {
a[u].tag = 1; a[u].siz = 1;
for (auto& son : a[u].e) {
if (son == fa || a[son].tag != 0)continue;
dfs2(son, u);
a[u].siz += a[son].siz;
}
} int mu[MX], vis[MX], p[MX], cnt;
void init() {
mu[1] = 1;
rep(i, 2, MX - 1) {
if (!vis[i])p[++cnt] = i, mu[i] = -1;
for (int j = 1; i * p[j] < MX; j++) {
vis[i * p[j]] = 1;
if (i % p[j] == 0)break;
mu[i * p[j]] = -mu[i];
}
}
} void eachT() {
set<int>fac;
rep(i, 1, n)a[i].e.clear(), a[i].tag = 0,a[i].siz=1; cin >> n >> x;
rep(i, 1, n - 1) {
int u, v; cin >> u >> v;
a[u].e.push_back(v), a[v].e.push_back(u);
}
rep(i, 1, n)cin >> a[i].val; for (int i = 1; i * i <= x; i++) {
if (x % i == 0)fac.insert(i), fac.insert(x / i);
} ll ans = 0;
for (auto& f : fac) {
ll now = 0;
dfs(1, 0, f);
rep(i, 1, n) {
if (a[i].tag == 0) {
dfs2(i, 0);
int s = a[i].siz;
now += s * (s - 1) / 2 + s;
}
}
ans += now * mu[x / f];
}
cout << ans << '\n';
}
signed main()
{
ios::sync_with_stdio(false);
cin.tie(0), cout.tie(0);
init();
ll t = 1;
cin >> t;
while (t--) { eachT(); }
}

快速莫比乌斯变换(FMT)与莫比乌斯反演 例题:树上lcm的更多相关文章

  1. 集合并卷积的三种求法(分治乘法,快速莫比乌斯变换(FMT),快速沃尔什变换(FWT))

    也许更好的阅读体验 本文主要内容是对武汉市第二中学吕凯风同学的论文<集合幂级数的性质与应用及其快速算法>的理解 定义 集合幂级数 为了更方便的研究集合的卷积,引入集合幂级数的概念 集合幂级 ...

  2. 快速莫比乌斯变换(FMT)

    快速莫比乌斯变换(FMT) 原文出处:虞大的博客.此仅作蒟蒻本人复习用~ 给定两个长度为n的序列 \(a_0, a_1, \cdots, a_{n-1}\)和\(b_0, b_1, \cdots, b ...

  3. 快速沃尔什变换&快速莫比乌斯变换小记

    u1s1 距离省选只剩 5 days 了,现在学新算法真的合适吗(( 位运算卷积 众所周知,对于最普通的卷积 \(c_i=\sum\limits_{j+k=i}a_jb_k\),\(a_jb_k\) ...

  4. BZOJ 4036: [HAOI2015]按位或 集合幂函数 莫比乌斯变换 莫比乌斯反演

    http://www.lydsy.com/JudgeOnline/problem.php?id=4036 http://blog.csdn.net/lych_cys/article/details/5 ...

  5. 快速沃尔什变换(FWT) 与 快速莫比乌斯变换 与 快速沃尔什变换公式推导

    后面的图片将会告诉: 如何推出FWT的公式tf 如何推出FWT的逆公式utf 用的是设系数,求系数的方法! ============================================== ...

  6. 快速傅立叶变换(FFT)

    多项式 系数表示法 设\(f(x)\)为一个\(n-1\)次多项式,则 \(f(x)=\sum\limits_{i=0}^{n-1}a_i*x_i\) 其中\(a_i\)为\(f(x)\)的系数,用这 ...

  7. 【算法】快速数论变换(NTT)初探

    [简介] 快速傅里叶变换(FFT)运用了单位复根的性质减少了运算,但是每个复数系数的实部和虚部是一个余弦和正弦函数,因此系数都是浮点数,而浮点数的运算速度较慢且可能产生误差等精度问题,因此提出了以数论 ...

  8. 为什么要进行傅立叶变换?傅立叶变换究竟有何意义?如何用Matlab实现快速傅立叶变换

    写在最前面:本文是我阅读了多篇相关文章后对它们进行分析重组整合而得,绝大部分内容非我所原创.在此向多位原创作者致敬!!!一.傅立叶变换的由来关于傅立叶变换,无论是书本还是在网上可以很容易找到关于傅立叶 ...

  9. 离散傅立叶变换与快速傅立叶变换(DFT与FFT)

    自从去年下半年接触三维重构以来,听得最多的词就是傅立叶变换,后来了解到这个变换在图像处理里面也是重点中的重点. 本身自己基于高数知识的理解是傅立叶变换是将一个函数变为一堆正余弦函数的和的变换.而图像处 ...

  10. 快速傅里叶变换 & 快速数论变换

    快速傅里叶变换 & 快速数论变换 [update 3.29.2017] 前言 2月10日初学,记得那时好像是正月十五放假那一天 当时写了手写版的笔记 过去近50天差不多忘光了,于是复习一下,具 ...

随机推荐

  1. 创建字符串对象的六种方法(java)

    package javaBasic; public class StringConstruction { public static void main(String[] args) { String ...

  2. 初识protobuf

    protobuf的优点 性能方面 序列化后,数据大小可缩小3倍 序列化速度快 传输速度快 使用方面 使用简单:proto编译器自动进行序列化和反序列化 维护成本低:多平台只需要维护一套对象协议文件,即 ...

  3. mysql安装配置启动

    1. 安装 & 配置 & 启动 MySQL现在的版本主要分为: 5.x 版本,现在互联网企业中的主流版本,包括:头条.美图.百度.腾讯等互联网公司主流的版本. 8.x 版本,新增了一些 ...

  4. VKProxy已提供命令行工具,镜像和简单的ui

    VKProxy 是使用c#开发的基于 Kestrel 实现 L4/L7的代理 经过6个月业余时间偶尔缝缝补补,已经达到能跑的地步了 (感兴趣的同学烦请点个github小赞赞呢) 相关使用写了一些简单的 ...

  5. MySQL事务:工作原理与实用指南

    MySQL事务:工作原理与实用指南 在数据库操作中,事务是保证数据一致性的重要机制.本文将深入探讨 MySQL 事务的特性.隔离级别以及实际应用场景,帮助你更好地理解和使用事务. 一.什么是事务? 事 ...

  6. 数栈产品预告丨您的指标管理平台——EasyIndex即将上线

    ​  一.写在前面 2016年,数栈开始正式投入研发,发展至今,已经拥有了:实时开发.离线开发.算法开发这些开发平台:数据资产.数据质量这些资产平台:以及数据服务.智能标签这些服务平台,这些不同类型的 ...

  7. hot100之堆

    虽然更多用的是桶 数组中的第k个最大元素(215) 桶排序 class Solution { public int findKthLargest(int[] nums, int k) { int[] ...

  8. .NET Core on K8S学习与实践系列文章 (2020版)

    一.关于这个系列 自从去年(2018年)底离开工作了3年的M公司加入X公司之后,开始了ASP.NET Core的实践,包括微服务架构与容器化等等.我们的实践是渐进的,当我们的微服务数量到了一定值时,发 ...

  9. Xamarin.Andorid 监听 EditText 回车事件

    EditText ET_Billcode.EditorAction += ET_Billcode_EditorAction; //执行方法 private void ET_Billcode_Edito ...

  10. MindManager:将excel转成思维导图

    当被要求把一个excel的内容转成思维导图的时,我讨要了很长的时间,使得有更多时间进行摸鱼,来完成本篇博客. 一:excel格式 绝不能使用合并单元格的方式,有合并的地方需要拆分,这是因为合并单元格后 ...