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

整理的算法模板合集: ACM模板


一、莫比乌斯反演

学习笔记,我是看这个博客入门的,讲的非常好,传送门,关键是给出了非常多的定理,好多是数论书上的权威概念。

我自己证明的照片在文末,有点乱

首先,莫比乌斯反演是什么?

第一种形式:

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)=dnf(d)=>f(n)=dnμ(d)F(dn)
第二种形式:

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(n)=ndf(d)=>f(n)=ndμ(nd)F(d)

二、几个概念和定理

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

  • ∑ d ∣ n \sum _{d|n} dn: 代表对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)=dnf(d)=>f(n)=dnμ(d)F(dn)
我们由恒等变形得:
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) f(n)=dnμ(d)F(dn)=dnμ(d)kdnf(k)=knf(k)dknμ(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} dnμ(d)={10n==1n>1
所以当且仅当 n k = 1 \frac{n}{k}=1 kn=1,即 n = k n=k n=k时, ∑ d ∣ n k μ ( d ) = 1 \sum_{d|\frac{n}{k}}\mu(d)=1 dknμ(d)=1,其余时候等于 0 0 0

∑ k ∣ n f ( k ) ∑ d ∣ n k μ ( d ) = f ( n ) \sum_{k|n}f(k)\sum_{d|\frac{n}{k}}\mu(d)=f(n) knf(k)dknμ(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) F(n)=ndf(d)=>f(n)=ndμ(nd)F(d)

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

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) f(n)=k=1+μ(k)F(nk)=k=1+μ(k)nktf(t)=ntf(t)kntμ(k)

所以当且仅当 t n = 1 \frac{t}{n}=1 nt=1,即 t = n t=n t=n时, ∑ k ∣ t n μ ( k ) = 1 \sum_{k|\frac{t}{n}}\mu(k)=1 kntμ(k)=1,其余时候等于 0 0 0
故得到

∑ n ∣ t f ( t ) ∑ k ∣ t n μ ( k ) = f ( n ) \sum_{n|t}f(t)\sum_{k|\frac{t}{n}}\mu(k)=f(n) ntf(t)kntμ(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 F F f f f。实际上,F和f的关系在于整除。我们可以假设

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

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

所以我们的目标就是求 f ( 1 ) \tt f(1) f(1), 而实际上可以看出F与f构成了一组莫比乌斯变换对。有了反演公式,我们可以通过求F来求f,而这里面F很好求,要求F(n)我们只要在原数组中数出到能被n整除的数的个数m, 则 C ( m , 4 ) \tt C(m,4) C(m,4)就是 F ( n ) \tt F(n) F(n)

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

我竟然在操作系统课上证明莫比乌斯反演?hhh
在这里插入图片描述
在这里插入图片描述

©️2020 CSDN 皮肤主题: 酷酷鲨 设计师:CSDN官方博客 返回首页