# 【学习笔记】莫比乌斯反演（包含定理，两种形式的证明及入门经典模板）

## 一、莫比乌斯反演

F ( n ) = ∑ d ∣ n f ( d ) = > f ( n ) = ∑ d ∣ n μ ( d ) F ( n d ) F(n)=\sum_{d|n}f(d)=>f(n)=\sum_{d|n}\mu(d)F(\frac{n}{d})

F ( n ) = ∑ n ∣ d f ( d ) = > f ( n ) = ∑ n ∣ d μ ( d n ) F ( d ) F(n)=\sum_{n|d}f(d)=>f(n)=\sum_{n|d}\mu(\frac{d}{n})F(d)

## 二、几个概念和定理

• 可乘函数（亦称积性函数）：算术函数 f f ，满足 只要 g c d ( m , n ) = 1 gcd(m,n) =1 ,就有 f ( m n ) = f ( m ) f ( n ) f(mn)=f(m)f(n)

• ∑ d ∣ n \sum _{d|n} ： 代表对n的所有正因子求和

• 莫比乌斯函数

## 三、两种形式的莫比乌斯反演证明

F ( n ) = ∑ d ∣ n f ( d ) = > f ( n ) = ∑ d ∣ n μ ( d ) F ( n d ) F(n)=\sum_{d|n}f(d)=>f(n)=\sum_{d|n}\mu(d)F(\frac{n}{d})

f ( n ) = ∑ d ∣ n μ ( d ) F ( n d ) = ∑ d ∣ n μ ( d ) ∑ k ∣ n d f ( k ) = ∑ k ∣ n f ( k ) ∑ d ∣ n k μ ( d ) f(n)=\sum_{d|n}\mu(d)F(\frac{n}{d})=\sum_{d|n}\mu(d)\sum_{k|\frac{n}{d}}f(k)=\sum_{k|n}f(k)\sum_{d|\frac{n}{k}}\mu(d)

∑ d ∣ n μ ( d ) = { 1 n = = 1 0 n > 1 \sum_{d|n}\mu(d)=\begin{cases}1&n==1\\0&n>1\end{cases}

∑ k ∣ n f ( k ) ∑ d ∣ n k μ ( d ) = f ( n ) \sum_{k|n}f(k)\sum_{d|\frac{n}{k}}\mu(d)=f(n)

F ( n ) = ∑ n ∣ d f ( d ) = > f ( n ) = ∑ n ∣ d μ ( d n ) F ( d ) F(n)=\sum_{n|d}f(d)=>f(n)=\sum_{n|d}\mu(\frac{d}{n})F(d)

k = d n k=\frac{d}{n} ，那么，就得到

f ( n ) = ∑ k = 1 + ∞ μ ( k ) F ( n k ) = ∑ k = 1 + ∞ μ ( k ) ∑ n k ∣ t f ( t ) = ∑ n ∣ t f ( t ) ∑ k ∣ t n μ ( k ) f(n)=\sum^{+\infty}_{k=1}\mu(k)F(nk)=\sum^{+\infty}_{k=1}\mu(k)\sum_{nk|t}f(t)=\sum_{n|t}f(t)\sum_{k|\frac{t}{n}}\mu(k)

∑ n ∣ t f ( t ) ∑ k ∣ t n μ ( k ) = f ( n ) \sum_{n|t}f(t)\sum_{k|\frac{t}{n}}\mu(k)=f(n)

## 四、POJ 3904 Sky Code（入门例题）

Stancu likes space travels but he is a poor software developer and will never be able to buy his own spacecraft. That is why he is preparing to steal the spacecraft of Petru. There is only one problem – Petru has locked the spacecraft with a sophisticated cryptosystem based on the ID numbers of the stars from the Milky Way Galaxy. For breaking the system Stancu has to check each subset of four stars such that the only common divisor of their numbers is 1. Nasty, isn’t it? Fortunately, Stancu has succeeded to limit the number of the interesting stars to N but, any way, the possible subsets of four stars can be too many. Help him to find their number and to decide if there is a chance to break the system.

• F ( n ) \tt F(n) 为有多少个四元组满足 g c d ( a , b , c , d ) = n \tt gcd(a,b,c,d)=n 整数倍

• f ( n ) \tt f(n) 为有多少个四元组满足 g c d ( a , b , c , d ) = n \tt gcd(a,b,c,d)=n

• n u m [ i ] num[i] 表示在输入的 n n 个数中有多少个是 i i 的倍数。
• F(i)表示的是在输入的 n n 个数中所有是i的倍数的这些数里挑选 4 4 个数的方案数。
• F ( i ) = C ( n u m [ i ] , 4 ) F(i) = C(num[i], 4)
• f ( n ) = Σ n ∣ d μ ( d / n ) F ( d ) f(n) = Σ_{n|d} μ(d/n)F(d) 其中 n = 1 n = 1
• 因为 n = 1 , n ∣ d n = 1,n|d ,所以d是所有范围(N)内的所有数。
• ∴ f ( n ) = μ ( 1 ) ∗ F ( 1 ) + μ ( 2 ) ∗ F ( 2 ) + ⋅ ⋅ ⋅ μ ( N ) ∗ F ( N ) ∴ f(n) = μ(1) * F(1) + μ(2) * F(2) + ···μ(N) * F(N)

#include<cstdio>
#include<cmath>
#include<algorithm>
#include<iostream>
#include<cstring>

using namespace std;
typedef long long ll;
const int N = 20007, M = 50007, INF = 0x3f3f3f3f;
const double eps = 1e-6;

int n, m;

int mu[N], vis[N];
int prime[N], cnt;
int num[N];
int a[N];
//mu(x) -> 1/-1/0
//if(x分解质因数之后所有次数为1)mu[x] = 1;
//else mu[x] = 0;
void get_mu(int n)//得到莫比乌斯函数
{
memset(vis, 0,sizeof vis);
memset(mu, 0, sizeof mu);
cnt = 0, mu[1] = 1;
for(int i = 2; i <= n;++ i){
if(!vis[i]){
prime[cnt ++ ] = i;
mu[i] = -1;//质数一定是-1
}
for(int j = 0; j < cnt && prime[j] * i <= n; ++ j){
vis[prime[j] * i] = 1;
if(i % prime[j] == 0)break;
mu[i * prime[j]] = -mu[i];
}
}
}

//num[i]表示在输入的n个数中有多少个是i的倍数
//F(i)表示的是在输入的n个数中所有是i的倍数的这些数里挑选4个数的方案数
//F(i) = C(num[i], 4)
//f(n) = Σ_{n|d} μ(d/n)F(d) 其中 n = 1
//因为n = 1,n|d,所以d是所有范围(N)内的所有数
//∴ f(n) = μ(1) * F(1) + μ(2) * F(2) + ···μ(N) * F(N)
void get_num()
{
memset(num, 0, sizeof num);
for(int i = 0; i < n; ++ i){
int x = a[i];
int m = sqrt(x);
for(int j = 1; j <= m; ++ j){
if(x % j == 0)//两个约数 ++ 表示这两个数多了一个倍数
num[j] ++ , num[x / j] ++ ;
}
if(m * m == x)num[m] -- ;//防止完全平方数多+1
}
}

ll Cn4(int m)
{
if(m == 0)return 0;
return 1ll * m * (m - 1) * (m - 2) * (m - 3) / 24;
}

int main()
{
get_mu(N);
while(scanf("%d", &n) != EOF){
for(int i = 0; i < n; ++ i)
scanf("%d", &a[i]);
get_num();
ll ans = 0;
for(int i = 1 ; i < N; ++ i)
ans += 1ll * mu[i] * Cn4(num[i]);
printf("%lld\n", ans);
}
return 0;
}



03-13 285

07-28 862
09-13 90
05-02 18
06-13
01-02 233
03-11 26
01-26 1211