一点数论——从零开始的莫比乌斯反演笔记(简单易懂)

1.前置知识

(1) 数论分块

之前写过专门说这个的了,传送门
大致是求形如
∑ i = 1 n ⌊ n i ⌋ \sum_{i=1}^{n} \lfloor \frac{n}{i} \rfloor i=1nin

代码也很短,主要是:

for(int l=1,r;l<=n;l=r+1)
{
	r=n/(n/l);
	ans+=(r-l+1)*(n/l);
}

(2)莫比乌斯函数

这是来自百度百科的解释:
在这里插入图片描述

简单来说就是

  1. n = 1 n=1 n=1时, μ ( n ) = 1 \mu(n)=1 μ(n)=1
  2. n n n分解质因数后,没有幂次大于平方的质因子, μ ( n ) = ( − 1 ) k \mu(n)=(-1)^k μ(n)=(1)k
  3. 只要当 n n n含有任何质因子的幂次大于等于2, μ ( n ) = 0 \mu(n)=0 μ(n)=0.

(3)狄利克雷卷积之常用性质1(非常重要/常用)

μ ∗ 1 = ϵ \mu * 1=\epsilon μ1=ϵ

对于任意正整数n
∑ d ∣ n μ ( d ) = ϵ ( n ) = [ n = 1 ] \sum_{d|n} \mu(d) = \epsilon(n) = [n=1] dnμ(d)=ϵ(n)=[n=1]
[ n = 1 ] [n=1] [n=1]表示只有当 n = 1 n=1 n=1成立时,返回值为1否则,值为0。

我们在莫比乌斯反演中套路是这样的:
[ g c d ( i , j ) = 1 ] = ∑ d ∣ g c d ( i , j ) μ ( d ) [ gcd(i,j)=1 ] = \sum_{d|gcd(i,j)} \mu(d) [gcd(i,j)=1]=dgcd(i,j)μ(d)

证明的话想到莫比乌斯函数这个性质就ok了:

(2) 狄利克雷卷积之常用性质2

ϕ ∗ 1 = I d \phi * 1 = Id ϕ1=Id

其中 I d Id Id函数表示 I d k ( x ) = x k Id_k(x) = x^k Idk(x)=xk

在这里插入图片描述

其实还有如下结论:
在这里插入图片描述

以及一条还不知道有啥用的公式:
∑ d ∣ n μ ( d ) d = ϕ ( n ) n \sum_{d|n} \frac{\mu(d)}{d} = \frac{ \phi(n) }{n} dndμ(d)=nϕ(n)

2.莫比乌斯反演

咱们终于进入正题啦!
在这里插入图片描述

定理

f ( n ) f(n) f(n) g ( n ) g(n) g(n)是定义在非负整数集合上的两个函数,并且满足条件:
f ( n ) = ∑ d ∣ n g ( d ) f(n) = \sum_{d|n}g(d) f(n)=dng(d)

那么有:
g ( n ) = ∑ d ∣ n μ ( d ) f ( ⌊ n d ⌋ ) g(n) = \sum_{d|n} \mu(d) f( \lfloor \frac{n}{d} \rfloor ) g(n)=dnμ(d)f(dn)

证明

方法一 数论推导

∑ d ∣ n μ ( d ) f ( n d ) = ∑ d ∣ n μ ( d ) ∑ k ∣ n d g ( k ) = ∑ k ∣ n g ( k ) ∑ d ∣ n k μ ( d ) = g ( n ) \sum_{d|n} \mu(d)f( \frac{n}{d} ) = \sum_{d|n}\mu(d) \sum_{k|\frac{n}{d}}g(k) = \sum_{k|n}g(k)\sum_{d|\frac{n}{k}}\mu(d) = g(n) dnμ(d)f(dn)=dnμ(d)kdng(k)=kng(k)dknμ(d)=g(n)

∑ k ∣ n d g ( k ) \sum_{k|\frac{n}{d}} g(k) kdng(k)代替 f ( n d ) f(\frac{n}{d}) f(dn),然后变换求和顺序,最后一步的依据是
∑ d ∣ n μ ( d ) = [ n = 1 ] \sum_{d|n} \mu(d) = [n=1] dnμ(d)=[n=1]




方法二 狄利克雷卷积推导
在这里插入图片描述

当然莫比乌斯反演还有另外一种形式:
如果有
f ( n ) = ∑ n ∣ d g ( d ) f(n) = \sum_{n|d}g(d) f(n)=ndg(d)
那么有
g ( n ) = ∑ n ∣ d μ ( d n ) f ( d ) g(n) = \sum_{n|d}\mu(\frac{d}{n})f(d) g(n)=ndμ(nd)f(d)

3.例题

我一看到那个需要设函数的莫比乌斯反演公式就烦躁,所以下面的推导决定不用那个公式。开始看例题前我们先回忆下这个公式:
[ g c d ( i , j ) = 1 ] = ∑ d ∣ g c d ( i , j ) μ ( d ) [gcd(i,j)=1] = \sum_{d|gcd(i,j)}\mu(d) [gcd(i,j)=1]=dgcd(i,j)μ(d)
(以下例题全部默认 n < m n<m n<m,且所有分式都是向下取整!!!)

例题1


∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) = 1 ] \sum_{i=1}^n \sum_{j=1}^m[gcd(i,j)=1] i=1nj=1m[gcd(i,j)=1]

我们直接套公式就好啦:
= ∑ i = 1 n ∑ j = 1 m ∑ d ∣ g c d ( i , j ) μ ( d ) = ∑ d = 1 n μ ( d ) ∑ i = 1 n d ∑ j = 1 m d = ∑ d = 1 n μ ( d ) ∗ ⌊ n d ⌋ ∗ ⌊ m d ⌋ =\sum_{i=1}^n \sum_{j=1}^m \sum_{d|gcd(i,j)} \mu(d) \\ =\sum_{d=1}^n \mu(d)\sum_{i=1}^\frac{n}{d} \sum_{j=1}^\frac{m}{d} \\ =\sum_{d=1}^n \mu(d) * \lfloor \frac{n}{d} \rfloor * \lfloor \frac{m}{d} \rfloor =i=1nj=1mdgcd(i,j)μ(d)=d=1nμ(d)i=1dnj=1dm=d=1nμ(d)dndm
我们会注意到后面那块是可以数论分块 O ( n ) O(\sqrt[]{n}) O(n )处理的




例题2


∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) = k ] \sum_{i=1}^n \sum_{j=1}^m [gcd(i,j)=k] i=1nj=1m[gcd(i,j)=k]
解法:
= ∑ i = 1 n ∑ j = 1 m [ g c d ( i k , j k ) = 1 ] = ∑ i = 1 n k ∑ j = 1 m k [ g c d ( i , j ) = 1 ] =\sum_{i=1}^n \sum_{j=1}^m[gcd( \frac{i}{k} , \frac{j}{k} )=1] \\ =\sum_{i=1}^{\frac{n}{k}}\sum_{j=1}^{\frac{m}{k}}[gcd(i,j)=1] =i=1nj=1m[gcd(ki,kj)=1]=i=1knj=1km[gcd(i,j)=1]




例题3

求:

∑ i = 1 n ∑ j = 1 m i j [ g c d ( i , j ) = k ] \sum_{i=1}^n \sum_{j=1}^mij[gcd(i,j)=k] i=1nj=1mij[gcd(i,j)=k]
解:
= ∑ i = 1 n ∑ j = 1 m i j [ g c d ( i k , j k ) = 1 ] = ∑ i = 1 n k ∑ j = 1 m k i j [ g c d ( i , j ) = 1 ] k 2 = ∑ i = 1 n k ∑ j = 1 m k i j k 2 ∑ d ∣ g c d ( i , j ) μ ( d ) = ∑ d = 1 n μ ( d ) d 2 ∑ i = 1 n k d ∑ j = 1 m k d i j k 2 =\sum_{i=1}^n \sum_{j=1}^m ij [gcd( \frac{i}{k} , \frac{j}{k} )=1] \\ =\sum_{i=1}^{\frac{n}{k}} \sum_{j=1}^{\frac{m}{k}} ij[gcd(i,j)=1]k^2 \\ =\sum_{i=1}^{\frac{n}{k}} \sum_{j=1}^{\frac{m}{k}} ijk^2 \sum_{d|gcd(i,j)} \mu(d) \\ =\sum_{d=1}^n \mu(d) d^2 \sum_{i=1}^{\frac{n}{kd}} \sum_{j=1}^{\frac{m}{kd}}ijk^2 =i=1nj=1mij[gcd(ki,kj)=1]=i=1knj=1kmij[gcd(i,j)=1]k2=i=1knj=1kmijk2dgcd(i,j)μ(d)=d=1nμ(d)d2i=1kdnj=1kdmijk2

这里要说一下

为什么会多一个 d 2 d^2 d2 k 2 k^2 k2 啊?

因为求和上下线限变了之后,gcd变成了可以用套路式换掉的样子,但是中间的 i j ij ij这一项缩小到了原来的 1 k 2 \frac{1}{k^2} k21倍,所以需要乘回去。 d 2 d^2 d2同理。

例题4


∑ i = 1 n ∑ j = 1 m l c m ( i , j ) \sum_{i=1}^n \sum_{j=1}^m lcm(i,j) i=1nj=1mlcm(i,j)

解:
= ∑ i = 1 n ∑ j = 1 m i j g c d ( i , j ) = ∑ d = 1 n ∑ i = 1 n ∑ j = 1 m i j d [ g c d ( i , j ) = d ] = ∑ d = 1 n ∑ i = 1 n d ∑ j = 1 m d i ∗ j ∗ d [ g c d ( i , j ) = 1 ] = ∑ d = 1 n ∑ i = 1 n d ∑ j = 1 m d i ∗ j ∗ d ∑ k ∣ g c d ( i , j ) μ ( k ) = ∑ d = 1 n d ∑ k = 1 n d μ ( k ) ∑ i = 1 n d k ∑ j = 1 m d k i ∗ j ∗ k 2 =\sum_{i=1}^n \sum_{j=1}^m \frac{ij}{gcd(i,j)} \\ =\sum_{d=1}^n \sum_{i=1}^n \sum_{j=1}^m\frac{ij}{d}[gcd(i,j)=d] \\ =\sum_{d=1}^n \sum_{i=1}^{\frac{n}{d}} \sum_{j=1}^{\frac{m}{d}}i*j*d[gcd(i,j)=1] \\ =\sum_{d=1}^n \sum_{i=1}^{\frac{n}{d}} \sum_{j=1}^{\frac{m}{d}}i*j*d \sum_{k|gcd(i,j)}\mu(k) \\ =\sum_{d=1}^n d \sum_{k=1}^{\frac{n}{d}}\mu(k) \sum_{i=1}^{\frac{n}{dk}} \sum_{j=1}^{\frac{m}{dk}}i*j*k^2 =i=1nj=1mgcd(i,j)ij=d=1ni=1nj=1mdij[gcd(i,j)=d]=d=1ni=1dnj=1dmijd[gcd(i,j)=1]=d=1ni=1dnj=1dmijdkgcd(i,j)μ(k)=d=1ndk=1dnμ(k)i=1dknj=1dkmijk2

4.练习题

T1 ZAP-Queries


∑ i = 1 n ∑ j = 1 m [ g c d ( i , j ) = k ] \sum_{i=1}^n \sum_{j=1}^m[gcd(i,j)=k] i=1nj=1m[gcd(i,j)=k]
解:
= ∑ i = 1 n k ∑ j = 1 m k [ g c d ( i , j ) = 1 ] = ∑ i = 1 n k ∑ j = 1 m k ∑ d ∣ g c d ( i , j ) μ ( d ) = ∑ d = 1 n k μ ( d ) ∑ i = 1 n k d ∑ j = 1 n k d = ∑ d = 1 n k μ ( d ) ⌊ n k d ⌋ ⌊ m k d ⌋ =\sum_{i=1}^{\frac{n}{k}} \sum_{j=1}^{\frac{m}{k}} [gcd(i,j)=1] \\ =\sum_{i=1}^{\frac{n}{k}} \sum_{j=1}^{\frac{m}{k}} \sum_{d|gcd(i,j)} \mu(d) \\ =\sum_{d=1}^{\frac{n}{k}} \mu(d) \sum_{i=1}^{\frac{n}{kd}} \sum_{j=1}^{\frac{n}{kd}} \\ =\sum_{d=1}^{\frac{n}{k}} \mu(d) \lfloor \frac{n}{kd} \rfloor \lfloor \frac{m}{kd} \rfloor =i=1knj=1km[gcd(i,j)=1]=i=1knj=1kmdgcd(i,j)μ(d)=d=1knμ(d)i=1kdnj=1kdn=d=1knμ(d)kdnkdm
先线性筛一下莫比乌斯函数,然后用一下整除分块就好啦

ACcode:

#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int N = 50100;

bool pd[N];
int n,m,k,mu[N],tot=0,pr[N];
LL sum[N];
void pre(int n)
{
	pd[1] = true;
	mu[1] = 1;
	for(int i=2;i<=n;i++)
	{
		if( pd[i]==false )
		{
			tot++;
			pr[tot] = i;
			mu[i] = -1;
		}
		for(int j=1;j<=tot&&i*pr[j]<=n;j++)
		{
			pd[ i*pr[j] ] = true;
			if( i%pr[j]==0 )
			{
//				mu[ i&pr[j] ] = 0;
				break;
			}
			else mu[ i*pr[j] ] = -mu[i];
		}
	}
	for(int i=1;i<=n;i++) sum[i] = sum[i-1] + mu[i];
}
LL ans = 0;
void solve()
{
	scanf("%d %d %d",&n,&m,&k);
	if( n>m ) swap(n,m);
	ans = 0;
	n /= k;
	m /= k;
	for(int l=1,r;l<=n;l=r+1)
	{
		r = min( n/(n/l) , m/(m/l) );
		ans += 1ll*(sum[r]-sum[l-1])*(n/l)*(m/l);
	}
	printf("%d\n",ans);
}

int main()
{
	//freopen("in.txt","r",stdin);
	pre(50000);
	int t;
	cin>>t;
	while( t-- )
	{
		solve();
	}
	return 0;
}

T2 Problem b

求:
∑ i = a b ∑ j = c d [ g c d ( i , j ) = k ] \sum_{i=a}^b \sum_{j=c}^d [gcd(i,j)=k] i=abj=cd[gcd(i,j)=k]
这题跟上题一模一样,只是多了个容斥。
a n s = a n s ( ( 1 , b ) , ( 1 , d ) ) − a n s ( ( 1 , b ) , ( 1 , c − 1 ) ) − a n s ( ( 1 , a − 1 ) , ( 1 , d ) ) + a n s ( ( 1 , a − 1 ) , ( 1 , c − 1 ) ) ans = ans((1,b),(1,d))−ans((1,b),(1,c−1))−ans((1,a−1),(1,d))+ans((1,a−1),(1,c−1)) ans=ans((1,b),(1,d))ans((1,b),(1,c1))ans((1,a1),(1,d))+ans((1,a1),(1,c1))

ACcode:

#include<bits/stdc++.h>
#define LL long long
#define N 50100
using namespace std;

int sum[N],ans;
int pr[N],tot = 0,mu[N],a,b,c,d,k;
bool pd[N];


void get_mu(int n)
{
	pd[1] = true;
	mu[1] = 1;
	for(int i=2;i<=n;i++)
	{
		if( pd[i]==false )
		{
			pr[++tot] = i;
			mu[i] = -1;
		}
		for(int j=1;j<=tot&&i*pr[j]<=n;j++)
		{
			pd[ i*pr[j] ] = true;
			if( i%pr[j]==0 ) break;
			else mu[ i*pr[j] ] = -mu[i];
		}
	}
	for(int i=1;i<=n;i++) sum[i] = sum[i-1] + mu[i];
}

LL cal(int n,int m)
{
	LL s = 0;
	n /= k;
	m /= k;
	if( n>m ) swap(n,m);
	for(int l=1,r;l<=n;l=r+1)
	{
		r = min( n/(n/l) , m/(m/l) );
		s += (LL)(sum[r]-sum[l-1]) * (LL)(n/l) * (LL)(m/l);
	}
	return s;
}

void solve()
{
	scanf("%d %d %d %d %d",&a,&b,&c,&d,&k);
	ans = cal( b,d ) - cal( a-1,d ) - cal( b,c-1 ) + cal( a-1,c-1 );
	printf("%d\n",ans);
}

int main()
{
	int t;
	cin>>t;
	get_mu(50000);
	while( t-- ) solve();
	return 0;
}

T3 [国家集训队]Crash的数字表格

求:
∑ i = 1 n ∑ j = 1 m l c m ( i , j ) \sum_{i=1}^n \sum_{j=1}^m lcm(i,j) i=1nj=1mlcm(i,j)

解:
= ∑ i = 1 n ∑ j = 1 m i j g c d ( i , j ) = ∑ d = 1 n ∑ i = 1 n ∑ j = 1 m i j d [ g c d ( i , j ) = d ] = ∑ d = 1 n ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ m d ⌋ i ∗ j ∗ d [ g c d ( i , j ) = 1 ] = ∑ d = 1 n ∑ i = 1 ⌊ n d ⌋ ∑ j = 1 ⌊ m d ⌋ i ∗ j ∗ d ∑ x ∣ g c d ( i , j ) μ ( x ) = ∑ d = 1 n ∑ x = 1 ⌊ n d ⌋ μ ( x ) ∗ x 2 ∑ i = 1 ⌊ n d x ⌋ ∑ j = 1 ⌊ m d x ⌋ i ∗ j = ∑ d = 1 n ∑ x = 1 ⌊ n d ⌋ μ ( x ) ∗ x 2 ∗ ⌊ n d x ⌋ ( 1 + ⌊ n d x ⌋ ) 2 ∗ ⌊ m d x ⌋ ( 1 + ⌊ m d x ⌋ ) 2 =\sum_{i=1}^n \sum_{j=1}^m \frac{ij}{gcd(i,j)} \\ =\sum_{d=1}^n\sum_{i=1}^n \sum_{j=1}^m\frac{ij}{d}[gcd(i,j)=d] \\ =\sum_{d=1}^n \sum_{i=1}^{ \lfloor \frac{n}{d} \rfloor }\sum_{j=1}^{ \lfloor \frac{m}{d} \rfloor }i*j*d[gcd(i,j)=1] \\ =\sum_{d=1}^n \sum_{i=1}^{ \lfloor \frac{n}{d} \rfloor }\sum_{j=1}^{ \lfloor \frac{m}{d} \rfloor }i*j*d\sum_{x|gcd(i,j)} \mu(x) \\ =\sum_{d=1}^n \sum_{x=1}^{ \lfloor \frac{n}{d} \rfloor } \mu(x)*x^2 \sum_{i=1}^{ \lfloor \frac{n}{dx} \rfloor } \sum_{j=1}^{ \lfloor \frac{m}{dx} \rfloor }i*j \\ =\sum_{d=1}^n \sum_{x=1}^{ \lfloor \frac{n}{d} \rfloor } \mu(x)*x^2 * \frac{\lfloor \frac{n}{dx} \rfloor(1+\lfloor \frac{n}{dx} \rfloor)}{2} *\frac{\lfloor \frac{m}{dx} \rfloor(1+\lfloor \frac{m}{dx} \rfloor)}{2} =i=1nj=1mgcd(i,j)ij=d=1ni=1nj=1mdij[gcd(i,j)=d]=d=1ni=1dnj=1dmijd[gcd(i,j)=1]=d=1ni=1dnj=1dmijdxgcd(i,j)μ(x)=d=1nx=1dnμ(x)x2i=1dxnj=1dxmij=d=1nx=1dnμ(x)x22dxn(1+dxn)2dxm(1+dxm)

Accode:

#include<bits/stdc++.h>
#define LL long long
#define N 10010000
using namespace std;
const LL M = 20101009;
int pr[N],tot=0,mu[N];
LL sum[N];
bool pd[N];
void get_mu(int x)
{
	pd[1] = false;
	mu[1] = 1;
	for(int i=2;i<=x;i++)
	{
		if( pd[i]==false )
		{
			tot++;
			pr[tot] = i;
			mu[i] = -1;
		}
		for(int j=1;j<=tot&&i*pr[j]<=x;j++)
		{
			pd[ i*pr[j] ] = true;
			if( i%pr[j]==0 ) break;
			mu[ i*pr[j] ] = -mu[i];
		}
	}
	for(int i=1;i<=x;i++)
	{
		sum[i] = ( sum[i-1] + 1LL*i*i%M*mu[i]%M )%M;
	}
}


LL cal(int x,int y) 
{
    return (1LL*x*(x+1)/2%M)*(1LL*y*(y+1)/2%M)%M;
}

LL func(int n,int m)
{
	LL ans = 0;
	for(int l=1,r;l<=n;l=r+1)
	{
		r = min( n/(n/l),m/(m/l) );
		ans = ( ans + ( sum[r]-sum[l-1] )*cal(n/l,m/l)%M )%M;
	}
	ans = (ans%M+M)%M;
	return ans;                                    
}

void solve()
{
	int n,m;
	LL ans = 0;
	scanf("%d %d",&n,&m);
	if( n>m ) swap(n,m);
	get_mu(n);
	for(int l=1,r;l<=n;l=r+1)
	{
		r = min( n/(n/l) , m/(m/l) );
		ans = ( ans + 1LL*( r-l+1 )*( r+l )/2%M * func(n/l,m/l)%M )%M;
	}
	ans = (ans+M)%M;
	printf("%lld\n",ans);
}


int main()
{
	solve();
	return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值