莫比乌斯反演学习笔记

前置知识

以下结论是显然的:

(1)若\(\theta\)可乘,则

  • \(\theta(1)=1\)
  • \(\theta(n)=\theta\left(p 1^{\alpha 1}\right) \theta\left(p 2^{\alpha 2}\right) \ldots \theta\left(p k^{\alpha k}\right)\)
  • \(\theta 1, \theta 2\) 可乘 \(\Longrightarrow \theta 1 \theta 2\) 可乘

(2)\(\sum_{d \mid n}\):对n所有的正因子求和
\(\left(\sum_{d \mid n} f(d)\right)\left(\sum_{d \mid n} g(d)\right)=\sum_{d_1|n \wedge d_2| n} f(d 1) g(d 2)\)

(3)【莫比乌斯函数】定义:

\[\mu(1)=1, \mu(n)=\mu\left(p 1^{\alpha 1}\right) \mu\left(p 2^{\alpha 2}\right) \ldots \mu\left(p k^{\alpha k}\right)=\left\{\begin{array}{l}(-1)^{k} \text { 若 } \alpha 1=\alpha 2=\ldots=\alpha k=1 \\ 0 \quad \text { otherwise }\end{array}\right. \]

显然,\(\mu\)为可乘函数

推论:

(4)若\(\theta\)可乘,则\(\psi(n)=\sum_{d \mid n} \theta(d)\)可乘(下文引用此处的\(\psi\)定义)

设( \(m, n)=1,\) 则mn的任一因子可唯一写成d \(=d 1 d 2\) 其中 \(d 1|m, d 2| n\),根据结论(2)

\[\psi(m n)=\sum_{d \mid m n} \theta(d)=\sum_{d_1|m\wedge d_2| n} \theta(d_1 d_2)=\sum_{d_1 \mid m} \sum_{d_2 \mid n} \theta(d 1 d 2)=\sum_{d 1 \mid m} \sum_{d 2 \mid n} \theta(d_1)\theta(d_2)= \psi(m)*\psi(n) \]

(5)\(\psi(n)=\left(1+\theta(p 1)+\theta\left(p 1^{2}\right)+\ldots\right)\left(1+\theta(p 2)+\theta\left(p 2^{2}\right)+. .\right) \ldots\)

该结论由3和可乘函数性质易得。

(6)若 \(\theta\) 可乘, \(\mu \theta\) 可乘, \(\sum_{d \mid n} \mu(d) \theta(d)\) 也可乘(根据性质4),易得

\[\sum_{d \mid n} \mu(d) \theta(d)=(1-\theta(p 1))(1-\theta(p 2)) \ldots .(1-\theta(p k)) \]

特别地,

\[\begin{alignat}{1}\theta(d) &= 1, \sum_{d \mid n} \mu(d)\theta(d)=\left\{\begin{array}{ll}1 & n=1 \\ 0 & \text { otherwise }\end{array}\right. \\\theta(d)&=\frac{1}{d}, \sum_{d \mid n} \mu(d)\theta(d)=\left(1-\frac{1}{p 1}\right)\left(1-\frac{1}{p 2}\right) \ldots\end{alignat} \]

(7)【莫比乌斯反演定理】

F(n)与f(n)均为数论函数

\[若满足F(n)=\sum_{d \mid n} f(d),则有f(n)=\sum_{d \mid n} \mu(d) F\left(\frac{n}{d}\right)(形式一) \\若满足F(n)=\sum_{n \mid d} f(d),则有f(n)=\sum_{n \mid d} \mu(\frac{d}{n}) F\left(d\right) (形式二) \]

证明:

\(\left(\left\{\begin{array}{l}d \mid n \\ d 1 \mid \frac{n}{d}\end{array} \Leftrightarrow\left\{\begin{array}{l}d \mid \frac{n}{d 1} \\ d 1 \mid n\end{array}\right)\right.\right.\)

\[\begin{alignat}{1}\sum_{d \mid n} \mu(d) F\left(\frac{n}{d}\right)&=\sum_{d \mid n} \mu(d) \sum_{d_1 \mid \frac{n}{d}} f(d 1) \\ &=\sum_{d \mid \frac{n}{d 1}} \mu(d) \sum_{d 1 \mid n} f(d 1) \\&=\sum_{d 1 \mid n} f(d 1) \sum_{d \mid \frac{n}{d 1}} \mu(d)\end{alignat} \]

根据性质(6)中\(\theta=1\)的情况,只有n=1时函数能取到1,因此只有\(\frac{n}{d_1}=1\)时该项对答案有贡献,即\(d_1=n\),因此\(\sum_{d 1 \mid n} f(d 1) \sum_{d \mid \frac{n}{d 1}} \mu(d)=f(n)\),形式一证毕

例题

POJ3904 Sky Code

题意:

给出n个数,问有多少4元组的gcd为1

思路:

直接求很困难,需要容斥,考虑进行转换:

设F(n):有多少四元组满足gcd为n的整数倍

f(n):有多少四元组满足gcd为n

F与f满足第二类反演条件\(F(n)=\sum_{n \mid d} f(d)\)

F(n)很好求,只要将包含因数n的数个数num预处理出来即可,\(F(n)=C(num,4)\)

答案即为f(1),可以通过反演第二种形式转换为求F(n),即

\[f(1)=\mu(1) F(1)+\mu(2) F(2)+\ldots \ldots+\mu(\max n) F(\max n)​ \]

代码:

#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
using namespace std;
typedef long long ll;
const int maxn=1e4+5;
const int maxp=1e4+5;
bool isPrime[maxn];
int Prime[maxp], primecnt = 0;
int mu[maxn];
void GetPrime(int n){//筛到n
	memset(isPrime, 1, sizeof(isPrime));
	isPrime[1] = 0;//1不是素数
	mu[1]=1;
	for(int i = 2; i <= n; i++){
		if(isPrime[i])//没筛掉
			Prime[++primecnt] = i, mu[i]=-1; //i成为下一个素数
		for(int j = 1; j <= primecnt && i*Prime[j] <= n; j++) {
			isPrime[i*Prime[j]] = 0;
			if(i % Prime[j] == 0){//i中也含有Prime[j]这个因子
			    mu[i*Prime[j]]=0;
				break;
			}
            else{
                mu[i*Prime[j]]=-mu[i];
            }
		}
	}
}
ll Cn4(ll n){
    if(n<=3){
        return 0;
    }
    else{
        return n*(n-1)*(n-2)*(n-3)/24;
    }
}
int a[maxn];
int tot[maxn];
void init(int n){
    memset(tot,0,sizeof tot);
}
int main () {
    const int N=10000;
    GetPrime(N);
    int n;
    while(~scanf("%d",&n)){
        init(n);
        for(int i=1;i<=n;i++){
            scanf("%d",&a[i]);
        }
        for(int i=1;i<=n;i++){
            int right=sqrt(a[i]);
            for(int j=1;j<=right;j++){
                if(a[i]%j==0){
                    tot[j]++;
                    tot[a[i]/j]++;
                }
            }
            if(right*right==a[i]){//多统计了一次
                tot[right]--;
            }
        }
        ll ans=0;
        for(int i=1;i<=maxn-1;i++){
            ans+=(ll)mu[i]*Cn4(tot[i]);
        }
        printf("%lld\n",ans);
    }
}

参考与引用:

https://blog.csdn.net/tomandjake_/article/details/81083051

https://blog.csdn.net/tomandjake_/article/details/81083703

posted @ 2020-08-13 09:58  UCPRER  阅读(148)  评论(0编辑  收藏  举报