莫比乌斯反演学习笔记
前置知识
以下结论是显然的:
(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\)为可乘函数
推论:
(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)
(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),易得
特别地,
(7)【莫比乌斯反演定理】
F(n)与f(n)均为数论函数
证明:
由\(\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.\),
根据性质(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),即
代码:
#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);
}
}
参考与引用: