8.12.22 ACM-ICPC数学 数论 莫比乌斯反演

8.12.22 ACM-ICPC数学 数论 莫比乌斯反演

引入

莫比乌斯反演是数论中的重要内容。对于一些函数 𝑓(𝑛)f(n),如果很难直接求出它的值,而容易求出其倍数和或约数和 𝑔(𝑛)g(n),那么可以通过莫比乌斯反演简化运算,求得 𝑓(𝑛)f(n) 的值。

在开始学习莫比乌斯反演前,需要先学习一些前置知识:数论分块、狄利克雷卷积。

莫比乌斯函数

定义

𝜇μ 为莫比乌斯函数,定义为

{1𝑛=10𝑛含有平方因子(−1)𝑘𝑘为 𝑛的本质不同质因子个数⎩⎨⎧​10(−1)k​n=1n含有平方因子k为 n的本质不同质因子个数​

详细解释如下: 令 𝑛=∏𝑖=1𝑘𝑝𝑖𝑐𝑖n=∏i=1k​pici​​,其中 𝑝𝑖pi​ 为质因子,𝑐𝑖≥1ci​≥1。上述定义表示:

  • 当 𝑛=1n=1 时,𝜇(𝑛)=1μ(n)=1;
  • 对于 𝑛≠1n=1 时:
    • 当存在 𝑖∈[1,𝑘]i∈[1,k],使得 𝑐𝑖>1ci​>1 时,𝜇(𝑛)=0μ(n)=0,也就是说只要某个质因子出现的次数超过一次,𝜇(𝑛)μ(n) 就等于 0;
    • 当任意 𝑖∈[1,𝑘]i∈[1,k],都有 𝑐𝑖=1ci​=1 时,𝜇(𝑛)=(−1)𝑘μ(n)=(−1)k,也就是说每个质因子都仅仅只出现过一次时,即 𝑛=∏𝑖=1𝑘𝑝𝑖n=∏i=1k​pi​,{𝑝𝑖}𝑖=1𝑘{pi​}i=1k​ 中个元素唯一时,𝜇(𝑛)μ(n) 等于 -1 的 𝑘k 次幂,此处 𝑘k 指的便是仅仅只出现过一次的质因子的总个数。

性质

莫比乌斯函数不仅是积性函数,还有如下性质:

{1𝑛=10𝑛≠1{10​n=1n=1​

即 ∑𝑑∣𝑛𝜇(𝑑)=𝜀(𝑛)∑d∣n​μ(d)=ε(n),𝜇∗1=𝜀μ∗1=ε

证明

设 𝑛=∏𝑖=1𝑘𝑝𝑖𝑐𝑖n=∏i=1k​pici​​, 𝑛′=∏𝑖=1𝑘𝑝𝑖n′=∏i=1k​pi​

那么 ∑𝑑∣𝑛𝜇(𝑑)=∑𝑑∣𝑛′𝜇(𝑑)=∑𝑖=0𝑘(𝑘𝑖)⋅(−1)𝑖=(1+(−1))𝑘∑d∣n​μ(d)=∑d∣n′​μ(d)=∑i=0k​(ik​)⋅(−1)i=(1+(−1))k

根据二项式定理,易知该式子的值在 𝑘=0k=0 即 𝑛=1n=1 时值为 1 否则为 0,这也同时证明了 ∑𝑑∣𝑛𝜇(𝑑)=[𝑛=1]=𝜀(𝑛)∑d∣n​μ(d)=[n=1]=ε(n) 以及 𝜇∗1=𝜀μ∗1=ε。

这个性质意味着,莫比乌斯函数在狄利克雷生成函数中,等价于黎曼函数 𝜁ζ 的倒数。所以在狄利克雷卷积中,莫比乌斯函数是常数函数 1 的逆元。

补充结论

反演结论: [gcd⁡(𝑖,𝑗)=1]=∑𝑑∣gcd⁡(𝑖,𝑗)𝜇(𝑑)[gcd(i,j)=1]=∑d∣gcd(i,j)​μ(d)

直接推导: 如果看懂了上一个结论,这个结论稍加思考便可以推出:如果 gcd⁡(𝑖,𝑗)=1gcd(i,j)=1 的话,那么代表着我们按上个结论中枚举的那个 𝑛n 是 1,也就是式子的值是 1,反之,有一个与 [\gcd(i, j) = 1] 相同的值:0

利用 𝜀ε 函数: 根据上一结论,[ gcd⁡(𝑖,𝑗)=1gcd(i,j)=1] = 𝜀(gcd⁡(𝑖,𝑗))ε(gcd(i,j)),将 𝜀ε 展开即可。

线性筛

由于 𝜇μ 函数为积性函数,因此可以线性筛莫比乌斯函数(线性筛基本可以求所有的积性函数,尽管方法不尽相同)。

线性筛实现
void getMu() {
  mu[1] = 1;
  for (int i = 2; i <= n; ++i) {
    if (!flg[i]) p[++tot] = i, mu[i] = -1;
    for (int j = 1; j <= tot && i * p[j] <= n; ++j) {
      flg[i * p[j]] = 1;
      if (i % p[j] == 0) {
        mu[i * p[j]] = 0;
        break;
      }
      mu[i * p[j]] = -mu[i];
    }
  }
}

拓展

证明: 𝜑∗1=id⁡φ∗1=id

将 𝑛n 分解质因数: 𝑛=∏𝑖=1𝑘𝑝𝑖𝑐𝑖n=∏i=1k​pici​​

首先,因为 𝜑φ 是积性函数,故只要证明当 𝑛′=𝑝𝑐n′=pc 时 𝜑∗1=∑𝑑∣𝑛′𝜑(𝑛′𝑑)=id⁡φ∗1=∑d∣n′​φ(dn′​)=id 成立即可。

因为 𝑝p 是质数,于是 𝑑=𝑝0,𝑝1,𝑝2,⋯ ,𝑝𝑐d=p0,p1,p2,⋯,pc

易知如下过程:

该式子两侧同时卷 𝜇μ 可得

莫比乌斯变换

设 𝑓(𝑛),𝑔(𝑛)f(n),g(n) 为两个数论函数。

形式一

如果有 那么有

这种形式下,数论函数 𝑓(𝑛)f(n) 称为数论函数 𝑔(𝑛)g(n) 的莫比乌斯变换,数论函数 𝑔(𝑛)g(n) 称为数论函数 𝑓(𝑛)f(n) 的莫比乌斯逆变换(反演)。

容易看出,数论函数 𝑔(𝑛)g(n) 的莫比乌斯变换,就是将数论函数 𝑔(𝑛)g(n) 与常数函数 1 进行狄利克雷卷积。

根据狄利克雷卷积与狄利克雷生成函数的对应关系,数论函数 𝑔(𝑛)g(n) 的莫比乌斯变换对应的狄利克雷生成函数,就是数论函数 𝑔(𝑛)g(n) 的狄利克雷生成函数与黎曼函数 𝜁ζ 的乘积。

形式二

如果有 𝑓(𝑛)=∑𝑛∣𝑑𝑔(𝑑)f(n)=∑n∣d​g(d),那么有

证明

方法一:对原式做数论变换。

方法二:运用卷积。 原问题为:已知 𝑓=𝑔∗1f=g∗1,证明 𝑔=𝑓∗𝜇g=f∗μ

易知如下转化:𝑓∗𝜇=𝑔∗1∗𝜇  ⟹  𝑓∗𝜇=𝑔f∗μ=g∗1∗μ⟹f∗μ=g(其中 1∗𝜇=𝜀1∗μ=ε)。

对于第二种形式: 类似上面的方法一,我们考虑逆推这个式子。

我们把 𝑑d 表示为 𝑘𝑛kn 的形式,然后把 𝑓f 的原定义代入式子。

发现枚举 𝑘k 再枚举 𝑘𝑛kn 的倍数可以转换为直接枚举 𝑛n 的倍数再求出 𝑘k,发现后面那一块其实就是 𝜀ε,整个式子只有在 𝑑=𝑛d=n 的时候才能取到值。

问题形式

「HAOI 2011」 Problem b 求值(多组数据)

根据容斥原理,原式可以分成 4 块来处理,每一块的式子都为

考虑化简该式子

因为 gcd⁡(𝑖,𝑗)=1gcd(i,j)=1 时对答案才用贡献,于是我们可以将其替换为 当且仅当 𝑛=1n=1 时值为 1 否则为 0),故原式化为

将 𝜀ε 函数展开得到

变换求和顺序,先枚举 𝑑∣gcd⁡(𝑖,𝑗)d∣gcd(i,j) 可得

易知 1∼⌊𝑛𝑘⌋1∼⌊kn​⌋ 中 𝑑d 的倍数有 ⌊𝑛𝑘𝑑⌋⌊kdn​⌋ 个,故原式化为

很显然,式子可以数论分块求解。

时间复杂度:Θ(𝑁+𝑇𝑛)Θ(N+Tn​)

代码实现
#include <algorithm>
#include <cstdio>
using namespace std;

const int N = 50000;
int mu[N + 5], p[N + 5];
bool flg[N + 5];

void init() {
  int tot = 0;
  mu[1] = 1;
  for (int i = 2; i <= N; ++i) {
    if (!flg[i]) {
      p[++tot] = i;
      mu[i] = -1;
    }
    for (int j = 1; j <= tot && i * p[j] <= N; ++j) {
      flg[i * p[j]] = 1;
      if (i % p[j] == 0) {
        mu[i * p[j]] = 0;
        break;
      }
      mu[i * p[j]] = -mu[i];
    }
  }
  for (int i = 1; i <= N; ++i) mu[i] += mu[i - 1];
}

int solve(int n, int m) {
  int res = 0;
  for (int i = 1, j; i <= min(n, m); i = j + 1) {
    j = min(n / (n / i), m / (m / i));
    res += (mu[j] - mu[i - 1]) * (n / i) * (m / i);  // 代推出来的式子
  }
  return res;
}

int main() {
  int T, a, b, c, d, k;
  init();  // 预处理mu数组
  scanf("%d", &T);
  for (int i = 1; i <= T; i++) {
    scanf("%d%d%d%d%d", &a, &b, &c, &d, &k);
    // 根据容斥原理,1<=x<=b&&1<=y<=d范围中的答案数减去1<=x<=b&&1<=y<=c-1范围中的答案数和
    //   1<=x<=a-1&&1<=y<=d范围中的答案数再加上1<=x<=a-1&&1<=y<=c-1范围中的答案数
    //   即可得到a<=x<=b&&c<=y<=d范围中的答案数
    // 这一步如果不懂可以画坐标图进行理解
    printf("%d\n", solve(b / k, d / k) - solve(b / k, (c - 1) / k) -
                       solve((a - 1) / k, d / k) +
                       solve((a - 1) / k, (c - 1) / k));
  }
  return 0;
}

例题

「SPOJ 5971」LCMSUM

求值(多组数据)

易得原式即

将原式复制一份并且颠倒顺序,然后将 𝑛n 一项单独提出,可得

根据 gcd⁡(𝑖,𝑛)=gcd⁡(𝑛−𝑖,𝑛)gcd(i,n)=gcd(n−i,n),可将原式化为

两个求和式中分母相同的项可以合并。

可以将相同的 gcd⁡(𝑖,𝑛)gcd(i,n) 合并在一起计算,故只需要统计 gcd⁡(𝑖,𝑛)=𝑑gcd(i,n)=d 的个数。当 gcd⁡(𝑖,𝑛)=𝑑gcd(i,n)=d 时,gcd⁡(𝑖𝑑,𝑛𝑑)=1gcd(di​,dn​)=1,所以 gcd⁡(𝑖,𝑛)=𝑑gcd(i,n)=d 的个数有 𝜑(𝑛𝑑)φ(dn​) 个。

故答案为

变换求和顺序,设 𝑑′=𝑛𝑑d′=dn​,合并公因式,式子化为 12𝑛⋅(∑𝑑′∣𝑛𝑑′⋅𝜑(𝑑′)+1)21​n⋅(∑d′∣n​d′⋅φ(d′)+1)

设 𝑔(𝑛)=∑𝑑∣𝑛𝑑⋅𝜑(𝑑)g(n)=∑d∣n​d⋅φ(d),已知 𝑔g 为积性函数,于是可以 Θ(𝑛)Θ(n) 筛出。每次询问 Θ(1)Θ(1) 计算即可。

下面给出这个函数筛法的推导过程:

首先考虑 𝑔(𝑝𝑗𝑘)g(pjk​) 的值,显然它的约数只有 𝑝𝑗0,𝑝𝑗1,⋯ ,𝑝𝑗𝑘pj0​,pj1​,⋯,pjk​,因此 𝑔(𝑝𝑗𝑘)=∑𝑤=0𝑘𝑝𝑗𝑤⋅𝜑(𝑝𝑗𝑤)g(pjk​)=∑w=0k​pjw​⋅φ(pjw​)

又有 则原式可化为

于是有

那么,对于线性筛中的 可得

同理有

代码实现
#include <cstdio>
const int N = 1000000;
int tot, p[N + 5];
long long g[N + 5];
bool flg[N + 5];  // 标记数组

void solve() {
  g[1] = 1;
  for (int i = 2; i <= N; ++i) {
    if (!flg[i]) {
      p[++tot] = i;
      g[i] = (long long)1 * i * (i - 1) + 1;
    }
    for (int j = 1; j <= tot && i * p[j] <= N; ++j) {
      flg[i * p[j]] = 1;
      if (i % p[j] == 0) {
        g[i * p[j]] =
            g[i] + (g[i] - g[i / p[j]]) * p[j] * p[j];  // 代入推出来的式子
        break;
      }
      g[i * p[j]] = g[i] * g[p[j]];
    }
  }
}

int main() {
  int T, n;
  solve();  // 预处理g数组
  scanf("%d", &T);
  for (int i = 1; i <= T; ++i) {
    scanf("%d", &n);
    printf("%lld\n", (g[n] + 1) * n / 2);
  }
  return 0;
}

  • 27
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

夏驰和徐策

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值