数论学习_莫比乌斯反演

背景:

之前不会用 M a r k d o w n Markdown ,所以坑没有补。

定义:

以下除法默认向下去整。
对于一个形如 F n = d n f d F_n=\sum_{d|n}f_d 的式子,用莫比乌斯反演得到了一个结论: f n = d n μ ( d ) F n / d f_n=\sum\limits_{d|n}μ(d)*F_{n/d}

证明可以考虑狄利克雷卷积(稍后补上)。

那么 μ μ 的定义是什么呢?
n = 1 n=1 时, μ ( n ) = 1 μ(n)=1
n > 1 n>1 时,若 n n 能分为 k k 个互不相等的质因数乘积,则 μ ( n ) = ( 1 ) k μ(n)=(-1)^k
否则, μ ( n ) = 0 μ(n)=0

同时 μ μ 是积性函数,因此可以用欧拉筛预处理 μ μ

用法:

可是怎么用呢。
我们发现 μ μ 函数存在一个性质: d n μ ( d ) = [ n = 1 ] \sum\limits_{d|n}μ(d)=[n=1]
证明可以考虑狄利克雷卷积(稍后补上)。

好像还是没有什么用(大雾…)?
别着急。

例题:

i = 1 n j = 1 n [ g c d ( i , j ) = 1 ] \sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}[gcd(i,j)=1]

对于这样的题怎么做呢?
显然暴力的时间复杂度是: Θ ( n 2 ) \Theta(n^2) 的。
好像很难…
细心的同学可以发现该式中的 g c d ( i , j ) = 1 gcd(i,j)=1 μ μ 性质 [ n = 1 ] [n=1] 有些类似,不妨将其套入,得:
i = 1 n j = 1 n d g c d ( i , j ) μ ( d ) \sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\sum\limits_{d|gcd(i,j)}μ(d)

更换枚举项,得:
i = 1 n j = 1 n d = 1 n μ ( d ) [ d g c d ( i , j ) ] \sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}\sum\limits_{d=1}^{n}μ(d)[d|gcd(i,j)]

d = 1 n μ ( d ) \sum\limits_{d=1}^{n}μ(d) 前置,得:
d = 1 n μ ( d ) i = 1 n j = 1 n [ d g c d ( i , j ) ] \sum\limits_{d=1}^{n}μ(d)\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{n}[d|gcd(i,j)]

更换枚举项,得:
d = 1 n μ ( d ) i = 1 n / d j = 1 n / d [ d ( g c d ( i , j ) d ) ] \sum\limits_{d=1}^{n}μ(d)\sum\limits_{i=1}^{n/d}\sum\limits_{j=1}^{n/d}[d|(gcd(i,j)*d)]

化简,得:
d = 1 n μ ( d ) i = 1 n / d j = 1 n / d 1 \sum\limits_{d=1}^{n}μ(d)\sum\limits_{i=1}^{n/d}\sum\limits_{j=1}^{n/d}1

最后,得:
d = 1 n μ ( d ) n d n d \sum\limits_{d=1}^{n}μ(d)*\Big\lfloor\dfrac{n}{d}\Big\rfloor*\Big\lfloor\dfrac{n}{d}\Big\rfloor

可以考虑用整除分块来加速,时间复杂度: Θ ( n ) \Theta(\sqrt{n})

代码:

以这道题 P 4450 P4450 双亲数P3455 [POI2007]ZAP-Queries的代码为例题目,但求的是 g c d ( i , j ) = k gcd(i,j)=k 的方案,具体可以看下面题表第一题的证明。

#include<cstdio>
#include<algorithm>
#include<cstring>
#define LL long long
using namespace std;
	int prime[1000010],mu[1000010],sum_mu[1000010];
	bool bz[1000010];
	int n,m,k;
void init(int ma)
{
	bz[0]=bz[1]=true;
	mu[1]=1;
	int t=0;
	for(int i=2;i<=ma;i++)
	{
		if(!bz[i]) prime[++t]=i,mu[i]=-1;
		for(int j=1;j<=t&&i*prime[j]<=ma;j++)
		{
			bz[i*prime[j]]=true;
			if(!(i%prime[j]))
			{
				mu[i*prime[j]]=0;
				break;
			}
			mu[i*prime[j]]=-mu[i];
		}
	}
	for(int i=1;i<=n;i++)
		sum_mu[i]=sum_mu[i-1]+mu[i];
}
LL solve(int n,int m,int k)
{
	LL sum=0;
	n/=k,m/=k;
	for(int l=1,r;l<=min(n,m);l=r+1)
	{
		r=min(n/(n/l),m/(m/l));
		sum+=((LL)n/l)*((LL)m/l)*((LL)sum_mu[r]-sum_mu[l-1]);
	}
	return sum;
}
int main()
{
	scanf("%d %d %d",&n,&m,&k);
	init(max(n,m));
	printf("%lld",solve(n,m,k));
}

总结

重点来了。
我们在化简式子时多考虑 , \sum,\prod 的性质,尝试化简。如果化简出形似 g c d ( i , j ) = 1 gcd(i,j)=1 的式子,可以考虑带入 μ μ 的性质,再化简即可。
一般都需要用整除分块的套路,同时,一些题目也需要预处理一些可以被证明的积性函数。

题表
luogu P2522 [HAOI2011]Problem b
luogu P2398 GCD SUM
luogu P1829 [国家集训队]Crash的数字表格 / JZPTAB
luogu P2257 YY的GCD
luogu P3327 [SDOI2015]约数个数和
luogu P3312 [SDOI2014]数表
luogu P3768 简单的数学题
luogu P4917 天守阁的地板
luogu P3704 [SDOI2017]数字表格

猜你喜欢

转载自blog.csdn.net/zsyz_ZZY/article/details/84952905