跳转至

莫比烏斯反演

引入

莫比烏斯反演是數論中的重要內容。對於一些函數 \(f(n)\),如果很難直接求出它的值,而容易求出其倍數和或約數和 \(g(n)\),那麼可以通過莫比烏斯反演簡化運算,求得 \(f(n)\) 的值。

開始學習莫比烏斯反演前,需要先學習一些前置知識:數論分塊狄利克雷卷積

莫比烏斯函數

定義

\(\mu\) 為莫比烏斯函數,定義為

\[ \mu(n)= \begin{cases} 1&n=1\\ 0&n\text{ 含有平方因子}\\ (-1)^k&k\text{ 為 }n\text{ 的本質不同質因子個數}\\ \end{cases} \]

詳細解釋一下:

\(n=\prod_{i=1}^kp_i^{c_i}\),其中 \(p_i\) 為質因子,\(c_i\ge 1\)。上述定義表示:

  1. \(n=1\) 時,\(\mu(n)=1\)
  2. 對於 \(n\not= 1\) 時:
    1. 當存在 \(i\in [1,k]\),使得 \(c_i > 1\) 時,\(\mu(n)=0\),也就是説只要某個質因子出現的次數超過一次,\(\mu(n)\) 就等於 \(0\)
    2. 當任意 \(i\in[1,k]\),都有 \(c_i=1\) 時,\(\mu(n)=(-1)^k\),也就是説每個質因子都僅僅只出現過一次時,即 \(n=\prod_{i=1}^kp_i\)\(\{p_i\}_{i=1}^k\) 中個元素唯一時,\(\mu(n)\) 等於 \(-1\)\(k\) 次冪,此處 \(k\) 指的便是僅僅只出現過一次的質因子的總個數。

性質

莫比烏斯函數不僅是積性函數,還有如下性質:

\[ \sum_{d\mid n}\mu(d)= \begin{cases} 1&n=1\\ 0&n\neq 1\\ \end{cases} \]

\(\sum_{d\mid n}\mu(d)=\varepsilon(n)\)\(\mu * 1 =\varepsilon\)

證明

\(\displaystyle n=\prod_{i=1}^k{p_i}^{c_i},n'=\prod_{i=1}^k p_i\)

那麼 \(\displaystyle\sum_{d\mid n}\mu(d)=\sum_{d\mid n'}\mu(d)=\sum_{i=0}^k \dbinom{k}{i}\cdot(-1)^i=(1+(-1))^k\)

根據二項式定理,易知該式子的值在 \(k=0\)\(n=1\) 時值為 \(1\) 否則為 \(0\),這也同時證明了 \(\displaystyle\sum_{d\mid n}\mu(d)=[n=1]=\varepsilon(n)\) 以及 \(\mu\ast 1=\varepsilon\)

這個性質意味着,莫比烏斯函數在狄利克雷生成函數中,等價於黎曼函數 \(\zeta\) 的倒數。所以在狄利克雷卷積中,莫比烏斯函數是常數函數 \(1\) 的逆元。

補充結論

反演結論:\(\displaystyle [\gcd(i,j)=1]=\sum_{d\mid\gcd(i,j)}\mu(d)\)

直接推導:如果看懂了上一個結論,這個結論稍加思考便可以推出:如果 \(\gcd(i,j)=1\) 的話,那麼代表着我們按上個結論中枚舉的那個 \(n\)\(1\),也就是式子的值是 \(1\),反之,有一個與 \([\gcd(i,j)=1]\) 相同的值:\(0\)

利用 \(\varepsilon\) 函數:根據上一結論,\([\gcd(i,j)=1]=\varepsilon(\gcd(i,j))\),將 \(\varepsilon\) 展開即可。

線性篩

由於 \(\mu\) 函數為積性函數,因此可以線性篩莫比烏斯函數(線性篩基本可以求所有的積性函數,儘管方法不盡相同)。

線性篩實現
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
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
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
def getMu():
mu[1] = 1
for i in range(2, n + 1):
    if flg[i] != 0:
        p[tot] = i; tot = tot + 1; mu[i] = -1
    j = 1
    while j <= tot and i * p[j] <= n:
        flg[i * p[j]] = 1
        if i % p[j] == 0:
            mu[i * p[j]] = 0
            break
        mu[i * p[j]] = mu[i * p[j]] - mu[i]
        j = j + 1

拓展

證明

\[ \varphi \ast 1=\operatorname{id} \]

\(n\) 分解質因數:\(\displaystyle n=\prod_{i=1}^k {p_i}^{c_i}\)

首先,因為 \(\varphi\) 是積性函數,故只要證明當 \(n'=p^c\)\(\displaystyle\varphi \ast 1=\sum_{d\mid n'}\varphi(\frac{n'}{d})=\operatorname{id}\) 成立即可。

因為 \(p\) 是質數,於是 \(d=p^0,p^1,p^2,\cdots,p^c\)

易知如下過程:

\[ \begin{aligned} \varphi \ast 1&=\sum_{d\mid n}\varphi(\frac{n}{d})\\ &=\sum_{i=0}^c\varphi(p^i)\\ &=1+p^0\cdot(p-1)+p^1\cdot(p-1)+\cdots+p^{c-1}\cdot(p-1)\\ &=p^c\\ &=\operatorname{id}\\ \end{aligned} \]

該式子兩側同時卷 \(\mu\) 可得 \(\displaystyle\varphi(n)=\sum_{d\mid n}d\cdot\mu(\frac{n}{d})\)


莫比烏斯變換

\(f(n),g(n)\) 為兩個數論函數。

形式一:如果有 \(f(n)=\sum_{d\mid n}g(d)\),那麼有 \(g(n)=\sum_{d\mid n}\mu(d)f(\frac{n}{d})\)

這種形式下,數論函數 \(f(n)\) 稱為數論函數 \(g(n)\) 的莫比烏斯變換,數論函數 \(g(n)\) 稱為數論函數 \(f(n)\) 的莫比烏斯逆變換(反演)。

容易看出,數論函數 \(g(n)\) 的莫比烏斯變換,就是將數論函數 \(g(n)\) 與常數函數 \(1\) 進行狄利克雷卷積。

根據狄利克雷卷積與狄利克雷生成函數的對應關係,數論函數 \(g(n)\) 的莫比烏斯變換對應的狄利克雷生成函數,就是數論函數 \(g(n)\) 的狄利克雷生成函數與黎曼函數 \(\zeta\) 的乘積。

形式二:如果有 \(f(n)=\sum_{n|d}g(d)\),那麼有 \(g(n)=\sum_{n|d}\mu(\frac{d}{n})f(d)\)

證明

方法一:對原式做數論變換。

\[ \sum_{d\mid n}\mu(d)f(\frac{n}{d})=\sum_{d\mid n}\mu(d)\sum_{k\mid \frac{n}{d}}g(k)=\sum_{k\mid n}g(k)\sum_{d\mid \frac{n}{k}}\mu(d)=g(n) \]

\(\displaystyle\sum_{d\mid n}g(d)\) 來替換 \(f(\dfrac{n}{d})\),再變換求和順序。最後一步變換的依據:\(\displaystyle\sum_{d\mid n}\mu(d)=[n=1]\),因此在 \(\dfrac{n}{k}=1\) 時第二個和式的值才為 \(1\)。此時 \(n=k\),故原式等價於 \(\displaystyle\sum_{k\mid n}[n=k]\cdot g(k)=g(n)\)

方法二:運用卷積。

原問題為:已知 \(f=g\ast1\),證明 \(g=f\ast\mu\)

易知如下轉化:\(f\ast\mu=g*1*\mu\implies f\ast\mu=g\)(其中 \(1\ast\mu=\varepsilon\))。

對於第二種形式:

類似上面的方法一,我們考慮逆推這個式子。

\[ \begin{aligned} &\sum_{n|d}{\mu(\frac{d}{n})f(d)} \\ =& \sum_{k=1}^{+\infty}{\mu(k)f(kn)} = \sum_{k=1}^{+\infty}{\mu(k)\sum_{kn|d}{g(d)}} \\ =& \sum_{n|d}{g(d)\sum_{k|\frac{d}{n}}{\mu(k)}} = \sum_{n|d}{g(d)\epsilon(\frac{d}{n})} \\ =& g(n) \end{aligned} \]

我們把 \(d\) 表示為 \(kn\) 的形式,然後把 \(f\) 的原定義代入式子。

發現枚舉 \(k\) 再枚舉 \(kn\) 的倍數可以轉換為直接枚舉 \(n\) 的倍數再求出 \(k\),發現後面那一塊其實就是 \(\epsilon\), 整個式子只有在 \(d=n\) 的時候才能取到值。


問題形式

「HAOI 2011」Problem b

求值(多組數據)

\[ \sum_{i=x}^{n}\sum_{j=y}^{m}[\gcd(i,j)=k]\qquad (1\leqslant T,x,y,n,m,k\leqslant 5\times 10^4) \]

根據容斥原理,原式可以分成 \(4\) 塊來處理,每一塊的式子都為

\[ \sum_{i=1}^{n}\sum_{j=1}^{m}[\gcd(i,j)=k] \]

考慮化簡該式子

\[ \sum_{i=1}^{\lfloor\frac{n}{k}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{k}\rfloor}[\gcd(i,j)=1] \]

因為 \(\gcd(i,j)=1\) 時對答案才用貢獻,於是我們可以將其替換為 \(\varepsilon(\gcd(i,j))\)\(\varepsilon(n)\) 當且僅當 \(n=1\) 時值為 \(1\) 否則為 \(0\)),故原式化為

\[ \sum_{i=1}^{\lfloor\frac{n}{k}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{k}\rfloor}\varepsilon(\gcd(i,j)) \]

\(\varepsilon\) 函數展開得到

\[ \displaystyle\sum_{i=1}^{\lfloor\frac{n}{k}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{k}\rfloor}\sum_{d\mid \gcd(i,j)}\mu(d) \]

變換求和順序,先枚舉 \(d\mid \gcd(i,j)\) 可得

\[ \displaystyle\sum_{d=1}\mu(d)\sum_{i=1}^{\lfloor\frac{n}{k}\rfloor}[d\mid i]\sum_{j=1}^{\lfloor\frac{m}{k}\rfloor}[d\mid j] \]

易知 \(1\sim\lfloor\dfrac{n}{k}\rfloor\)\(d\) 的倍數有 \(\lfloor\dfrac{n}{kd}\rfloor\) 個,故原式化為

\[ \displaystyle\sum_{d=1}^{\min(\lfloor \frac{n}{k}\rfloor,\lfloor \frac{m}{k}\rfloor)}\mu(d)\lfloor\frac{n}{kd}\rfloor\lfloor\frac{m}{kd}\rfloor \]

很顯然,式子可以數論分塊求解。

時間複雜度 \(\Theta(N+T\sqrt{n})\)

代碼實現
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#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

求值(多組數據)

\[ \sum_{i=1}^n \operatorname{lcm}(i,n)\quad \text{s.t.}\ 1\leqslant T\leqslant 3\times 10^5,1\leqslant n\leqslant 10^6 \]

易得原式即

\[ \sum_{i=1}^n \frac{i\cdot n}{\gcd(i,n)} \]

將原式複製一份並且顛倒順序,然後將 n 一項單獨提出,可得

\[ \frac{1}{2}\cdot \left(\sum_{i=1}^{n-1}\frac{i\cdot n}{\gcd(i,n)}+\sum_{i=n-1}^{1}\frac{i\cdot n}{\gcd(i,n)}\right)+n \]

根據 \(\gcd(i,n)=\gcd(n-i,n)\),可將原式化為

\[ \frac{1}{2}\cdot \left(\sum_{i=1}^{n-1}\frac{i\cdot n}{\gcd(i,n)}+\sum_{i=n-1}^{1}\frac{i\cdot n}{\gcd(n-i,n)}\right)+n \]

兩個求和式中分母相同的項可以合併。

\[ \frac{1}{2}\cdot \sum_{i=1}^{n-1}\frac{n^2}{\gcd(i,n)}+n \]

\[ \frac{1}{2}\cdot \sum_{i=1}^{n}\frac{n^2}{\gcd(i,n)}+\frac{n}{2} \]

可以將相同的 \(\gcd(i,n)\) 合併在一起計算,故只需要統計 \(\gcd(i,n)=d\) 的個數。當 \(\gcd(i,n)=d\) 時,\(\displaystyle\gcd(\frac{i}{d},\frac{n}{d})=1\),所以 \(\gcd(i,n)=d\) 的個數有 \(\displaystyle\varphi(\frac{n}{d})\) 個。

故答案為

\[ \frac{1}{2}\cdot\sum_{d\mid n}\frac{n^2\cdot\varphi(\frac{n}{d})}{d}+\frac{n}{2} \]

變換求和順序,設 \(\displaystyle d'=\frac{n}{d}\),合併公因式,式子化為

\[ \frac{1}{2}n\cdot\left(\sum_{d'\mid n}d'\cdot\varphi(d')+1\right) \]

\(\displaystyle \operatorname{g}(n)=\sum_{d\mid n} d\cdot\varphi(d)\),已知 \(\operatorname{g}\) 為積性函數,於是可以 \(\Theta(n)\) 篩出。每次詢問 \(\Theta(1)\) 計算即可。

下面給出這個函數篩法的推導過程:

首先考慮 \(\operatorname g(p_j^k)\) 的值,顯然它的約數只有 \(p_j^0,p_j^1,\cdots,p_j^k\),因此

\[ \operatorname g(p_j^k)=\sum_{w=0}^{k}p_j^w\cdot\varphi(p_j^w) \]

又有 \(\varphi(p_j^w)=p_j^{w-1}\cdot(p_j-1)\),則原式可化為

\[ \sum_{w=0}^{k}p_j^{2w-1}\cdot(p_j-1) \]

於是有

\[ \operatorname g(p_j^{k+1})=\operatorname g(p_j^k)+p_j^{2k+1}\cdot(p_j-1) \]

那麼,對於線性篩中的 \(\operatorname g(i\cdot p_j)(p_j|i)\),令 \(i=a\cdot p_j^w(\operatorname{gcd}(a,p_j)=1)\),可得

\[ \operatorname g(i\cdot p_j)=\operatorname g(a)\cdot\operatorname g(p_j^{w+1}) \]
\[ \operatorname g(i)=\operatorname g(a)\cdot\operatorname g(p_j^w) \]

\[ \operatorname g(i\cdot p_j)-\operatorname g(i)=\operatorname g(a)\cdot p_j^{2w+1}\cdot(p_j-1) \]

同理有

\[ \operatorname g(i)-\operatorname g(\frac{i}{p_j})=\operatorname g(a)\cdot p_j^{2w-1}\cdot(p_j-1) \]

因此

\[ \operatorname g(i\cdot p_j)=\operatorname g(i)+\left (\operatorname g(i)-\operatorname g(\frac{i}{p_j})\right )\cdot p_j^2 \]

時間複雜度\(\Theta(n+T)\)

代碼實現
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#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;
}

「BZOJ 2154」Crash 的數字表格

求值(對 \(20101009\) 取模)

\[ \sum_{i=1}^n\sum_{j=1}^m\operatorname{lcm}(i,j)\qquad (n,m\leqslant 10^7) \]

易知原式等價於

\[ \sum_{i=1}^n\sum_{j=1}^m\frac{i\cdot j}{\gcd(i,j)} \]

枚舉最大公因數 \(d\),顯然兩個數除以 \(d\) 得到的數互質

\[ \sum_{i=1}^n\sum_{j=1}^m\sum_{d\mid i,d\mid j,\gcd(\frac{i}{d},\frac{j}{d})=1}\frac{i\cdot j}{d} \]

非常經典的 \(\gcd\) 式子的化法

\[ \sum_{d=1}^n d\cdot\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}[\gcd(i,j)=1]\ i\cdot j \]

後半段式子中,出現了互質數對之積的和,為了讓式子更簡潔就把它拿出來單獨計算。於是我們記

\[ \operatorname{sum}(n,m)=\sum_{i=1}^n\sum_{j=1}^m [\gcd(i,j)=1]\ i\cdot j \]

接下來對 \(\operatorname{sum}(n,m)\) 進行化簡。首先枚舉約數,並將 \([\gcd(i,j)=1]\) 表示為 \(\varepsilon(\gcd(i,j))\)

\[ \sum_{d=1}^n\sum_{d\mid i}^n\sum_{d\mid j}^m\mu(d)\cdot i\cdot j \]

\(i=i'\cdot d\)\(j=j'\cdot d\),顯然式子可以變為

\[ \sum_{d=1}^n\mu(d)\cdot d^2\cdot\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{d}\rfloor}i\cdot j \]

觀察上式,前半段可以預處理前綴和;後半段又是一個範圍內數對之和,記

\[ g(n,m)=\sum_{i=1}^n\sum_{j=1}^m i\cdot j=\frac{n\cdot(n+1)}{2}\times\frac{m\cdot(m+1)}{2} \]

可以 \(\Theta(1)\) 求解

至此

\[ \operatorname{sum}(n,m)=\sum_{d=1}^n\mu(d)\cdot d^2\cdot g(\lfloor\frac{n}{d}\rfloor,\lfloor\frac{m}{d}\rfloor) \]

我們可以 \(\lfloor\frac{n}{\lfloor\frac{n}{d}\rfloor}\rfloor\) 數論分塊求解 \(\operatorname{sum}(n,m)\) 函數。

在求出 \(\operatorname{sum}(n,m)\) 後,回到定義 \(\operatorname{sum}\) 的地方,可得原式為

\[ \sum_{d=1}^n d\cdot\operatorname{sum}(\lfloor\frac{n}{d}\rfloor,\lfloor\frac{m}{d}\rfloor) \]

可見這又是一個可以數論分塊求解的式子!

本題除了推式子比較複雜、代碼細節較多之外,是一道很好的莫比烏斯反演練習題!(上述過程中,默認 \(n\leqslant m\)

時間複雜度:\(\Theta(n+m)\)(瓶頸為線性篩)

代碼實現
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <algorithm>
#include <cstdio>
using namespace std;

const int N = 1e7;
const int mod = 20101009;
int n, m, mu[N + 5], p[N / 10 + 5], sum[N + 5];
bool flg[N + 5];

int Sum(int x, int y) {
  return ((long long)1 * x * (x + 1) / 2 % mod) *
         ((long long)1 * y * (y + 1) / 2 % mod) % mod;
}

int func(int x, int y) {
  int res = 0;
  int j;
  for (int i = 1; i <= min(x, y); i = j + 1) {
    j = min(x / (x / i), y / (y / i));
    res = (res + (long long)1 * (sum[j] - sum[i - 1] + mod) *
                     Sum(x / i, y / i) % mod) %
          mod;  //+mod防负数
  }
  return res;
}

int solve(int x, int y) {
  int res = 0;
  int j;
  for (int i = 1; i <= min(x, y); i = j + 1) {  // 整除分块处理
    j = min(x / (x / i), y / (y / i));
    res = (res + (long long)1 * (j - i + 1) * (i + j) / 2 % mod *
                     func(x / i, y / i) % mod) %
          mod;  // !每步取模防爆
  }
  return res;
}

void init() {  // 线性筛
  mu[1] = 1;
  int tot = 0, k = min(n, m);
  for (int i = 2; i <= k; ++i) {
    if (!flg[i]) {
      p[++tot] = i;
      mu[i] = -1;
    }
    for (int j = 1; j <= tot && i * p[j] <= k; ++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 <= k; ++i)
    sum[i] = (sum[i - 1] + (long long)1 * i * i % mod * (mu[i] + mod)) % mod;
}

int main() {
  scanf("%d%d", &n, &m);
  init();
  printf("%d\n", solve(n, m));
}

「SDOI2015」約數個數和

多組數據,求

\[ \sum_{i=1}^n\sum_{j=1}^md(i\cdot j) \qquad \left(n,m,T\leq5\times10^4\right) \]

其中 \(d(n)=\sum_{i \mid n}1\)\(d(n)\) 表示 \(n\) 的約數個數

要推這道題首先要了解 \(d\) 函數的一個特殊性質

\[ d(i\cdot j)=\sum_{x \mid i}\sum_{y \mid j}[\gcd(x,y)=1] \]

再化一下這個式子

\[ \begin{aligned} d(i\cdot j)=&\sum_{x \mid i}\sum_{y \mid j}[\gcd(x,y)=1]\\ =&\sum_{x \mid i}\sum_{y \mid j}\sum_{p \mid \gcd(x,y)}\mu(p)\\ =&\sum_{p=1}^{min(i,j)}\sum_{x \mid i}\sum_{y \mid j}[p \mid \gcd(x,y)]\cdot\mu(p)\\ =&\sum_{p \mid i,p \mid j}\mu(p)\sum_{x \mid i}\sum_{y \mid j}[p \mid \gcd(x,y)]\\ =&\sum_{p \mid i,p \mid j}\mu(p)\sum_{x \mid \frac{i}{p}}\sum_{y \mid \frac{j}{p}}1\\ =&\sum_{p \mid i,p \mid j}\mu(p)d\left(\frac{i}{p}\right)d\left(\frac{j}{p}\right)\\ \end{aligned} \]

將上述式子代回原式

\[ \begin{aligned} &\sum_{i=1}^n\sum_{j=1}^md(i\cdot j)\\ =&\sum_{i=1}^n\sum_{j=1}^m\sum_{p \mid i,p \mid j}\mu(p)d\left(\frac{i}{p}\right)d\left(\frac{j}{p}\right)\\ =&\sum_{p=1}^{min(n,m)} \sum_{i=1}^n\sum_{j=1}^m [p \mid i,p \mid j]\cdot\mu(p)d\left(\frac{i}{p}\right)d\left(\frac{j}{p}\right)\\ =&\sum_{p=1}^{min(n,m)} \sum_{i=1}^{\left\lfloor\frac{n}{p}\right\rfloor}\sum_{j=1}^{\left\lfloor\frac{m}{p}\right\rfloor} \mu(p)d(i)d(j)\\ =&\sum_{p=1}^{min(n,m)}\mu(p) \sum_{i=1}^{\left\lfloor\frac{n}{p}\right\rfloor}d(i) \sum_{j=1}^{\left\lfloor\frac{m}{p}\right\rfloor}d(j)\\ =&\sum_{p=1}^{min(n,m)}\mu(p) S\left(\left\lfloor\frac{n}{p}\right\rfloor\right) S\left(\left\lfloor\frac{m}{p}\right\rfloor\right) \left(S(n)=\sum_{i=1}^{n}d(i)\right)\\ \end{aligned} \]

那麼 \(O(n)\) 預處理 \(\mu,d\) 的前綴和,\(O(\sqrt{n})\) 分塊處理詢問,總複雜度 \(O(n+T\sqrt{n})\).

代碼實現
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <algorithm>
#include <cstdio>
using namespace std;
const long long N = 5e4 + 5;
long long n, m, T, pr[N], mu[N], d[N], t[N],
    cnt;  // t 表示 i 的最小质因子出现的次数
bool bp[N];

void prime_work(long long k) {
  bp[0] = bp[1] = 1, mu[1] = 1, d[1] = 1;
  for (long long i = 2; i <= k; i++) {  // 线性筛
    if (!bp[i]) pr[++cnt] = i, mu[i] = -1, d[i] = 2, t[i] = 1;
    for (long long j = 1; j <= cnt && i * pr[j] <= k; j++) {
      bp[i * pr[j]] = 1;
      if (i % pr[j] == 0) {
        mu[i * pr[j]] = 0;
        d[i * pr[j]] = d[i] / (t[i] + 1) * (t[i] + 2);
        t[i * pr[j]] = t[i] + 1;
        break;
      } else {
        mu[i * pr[j]] = -mu[i];
        d[i * pr[j]] = d[i] << 1;
        t[i * pr[j]] = 1;
      }
    }
  }
  for (long long i = 2; i <= k; i++)
    mu[i] += mu[i - 1], d[i] += d[i - 1];  // 求前缀和
}

long long solve() {
  long long res = 0, mxi = min(n, m);
  for (long long i = 1, j; i <= mxi; i = j + 1) {  // 整除分块
    j = min(n / (n / i), m / (m / i));
    res += d[n / i] * d[m / i] * (mu[j] - mu[i - 1]);
  }
  return res;
}

int main() {
  scanf("%lld", &T);
  prime_work(50000);  // 预处理
  while (T--) {
    scanf("%lld%lld", &n, &m);
    printf("%lld\n", solve());
  }
  return 0;
}

莫比烏斯反演擴展

結尾補充一個莫比烏斯反演的非卷積形式。

對於數論函數 \(f,g\) 和完全積性函數 \(t\)\(t(1)=1\)

\[ \begin{gathered} f(n)=\sum_{i=1}^nt(i)g\left(\left\lfloor\frac{n}{i}\right\rfloor\right)\\ \iff\\ g(n)=\sum_{i=1}^n\mu(i)t(i)f\left(\left\lfloor\frac{n}{i}\right\rfloor\right) \end{gathered} \]

我們證明一下

\[ \begin{aligned} g(n)&=\sum_{i=1}^n\mu(i)t(i)f\left(\left\lfloor\frac{n}{i}\right\rfloor\right)\\ &=\sum_{i=1}^n\mu(i)t(i) \sum_{j=1}^{\left\lfloor\frac{n}{i}\right\rfloor}t(j) g\left(\left\lfloor\frac{\left\lfloor\frac{n}{i}\right\rfloor}{j}\right\rfloor\right)\\ &=\sum_{i=1}^n\mu(i)t(i) \sum_{j=1}^{\left\lfloor\frac{n}{i}\right\rfloor}t(j) g\left(\left\lfloor\frac{n}{ij}\right\rfloor\right)\\ &=\sum_{T=1}^n \sum_{i=1}^n\mu(i)t(i) \sum_{j=1}^{\left\lfloor\frac{n}{i}\right\rfloor}[ij=T] t(j)g\left(\left\lfloor\frac{n}{T}\right\rfloor\right) &\text{【先枚舉 ij 乘積】}\\ &=\sum_{T=1}^n \sum_{i \mid T}\mu(i)t(i) t\left(\frac{T}{i}\right)g\left(\left\lfloor\frac{n}{T}\right\rfloor\right) &\text{【}\sum_{j=1}^{\left\lfloor\frac{n}{i}\right\rfloor}[ij=T] \text{對答案的貢獻為 1,於是省略】}\\ &=\sum_{T=1}^ng\left(\left\lfloor\frac{n}{T}\right\rfloor\right) \sum_{i \mid T}\mu(i)t(i)t\left(\frac{T}{i}\right)\\ &=\sum_{T=1}^ng\left(\left\lfloor\frac{n}{T}\right\rfloor\right) \sum_{i \mid T}\mu(i)t(T) &\text{【t 是完全積性函數】}\\ &=\sum_{T=1}^ng\left(\left\lfloor\frac{n}{T}\right\rfloor\right)t(T) \sum_{i \mid T}\mu(i)\\ &=\sum_{T=1}^ng\left(\left\lfloor\frac{n}{T}\right\rfloor\right)t(T) \varepsilon(T) &\text{【}\mu\ast 1= \varepsilon\text{】}\\ &=g(n)t(1) &\text{【當且僅當 T=1,}\varepsilon(T)=1\text{時】}\\ &=g(n) & \square \end{aligned} \]

參考文獻

algocode 算法博客