莫比乌斯反演

前置知识:积性函数。具体可以看我的博客(积性函数专题) https://www.cnblogs.com/czyty114/p/12707134.html

莫比乌斯反演

(;)
如果(F(n)=sum_{d|n} f(d))
(f(n)=sum_{d|n} mu (d) F(frac{n}{d}))

证明

(;)
看到网上很多人的证明都是推了一大堆的式子,本人表示瑟瑟发抖,这里推荐神葱的一种简单证明方法。

[ecause F(n)=sum_{d|n} f(d) ]

[ herefore F= f*I ]

[ herefore F*mu=f*I*mu ]

[ herefore F*mu=f*(I*mu)=f*epsilon ]

显然,(f*epsilon=f)

[ herefore F*mu=f ]

[f(n)=sum_{d|n} mu (d) F(frac{n}{d}) ]

(Q.E.D)
(;)
(;)

几道经典的好题

Problem 1

(;)
求:(sum_{i=1}^n sum_{j=1}^m gcd(i,j);;;;n,m leq 10^7)
在含有多个(sum)(prod)这样的式子中,你要知道有几个基本套路(增加枚举量,交换枚举量),下面会一一说明
啥都别说了,推式子吧。

[sum_{i=1}^n sum_{j=1}^m gcd(i,j) ]

[=sum_{i=1}^n sum_{j=1}^m id(gcd(i,j)) ]

增加枚举量:

[=sum_{i=1}^n sum_{j=1}^m sum_{d|gcd(i,j)} phi (d) ]

交换枚举量:

[=sum_{d=1}^{min(n,m)} sum_{i=1}^{lfloor frac{n}{d} floor} sum_{j=1}^{lfloor frac{m}{d} floor} phi (d) ]

[=sum_{d=1}^{min(n,m)} phi(d) sum_{i=1}^{lfloor frac{n}{d} floor} sum_{j=1}^{lfloor frac{m}{d} floor} 1 ]

[=sum_{d=1}^{min(n,m)} phi(d) lfloor frac{n}{d} floor lfloor frac{m}{d} floor ]

所以我们直接预处理出(phi (1-min(n,m)))即可
时间复杂度:(O(n))
题目地址: https://www.luogu.com.cn/problem/U114004
(;)
(;)

Problem 2

(;)
求:(sum_{i=1}^n sum_{j=1}^m lcm(i,j);;;;n,m leq 10^7)
感觉和上道题差不多?其实要难些。
推导:

[sum_{i=1}^n sum_{j=1}^m lcm(i,j) ]

根据(lcm(i,j)=frac{ij}{gcd(i,j)})

[=sum_{i=1}^n sum_{j=1}^m frac{ij}{gcd(i,j)} ]

枚举(gcd(i,j)=d)

[=sum_{d=1}^{min(n,m)}sum_{i=1}^n sum_{j=1}^m [gcd(i,j)=d]frac{ij}{d} ]

(d)提出来

[=sum_{d=1}^{min(n,m)} frac{1}{d} sum_{i=1}^n sum_{j=1}^m [gcd(i,j)=d]ij ]

[=sum_{d=1}^{min(n,m)} frac{1}{d} sum_{i=1}^{lfloor frac{n}{d} floor} sum_{j=1}^{lfloor frac{m}{d} floor} [gcd(i,j)=1]idjd ]

[=sum_{d=1}^{min(n,m)} d sum_{i=1}^{lfloor frac{n}{d} floor} sum_{j=1}^{lfloor frac{m}{d} floor} [gcd(i,j)=1]ij ]

我们把后面的式子挑出来。

[S(n,m)=sum_{i=1}^{n} sum_{j=1}^{m} [gcd(i,j)=1]ij ]

[=sum_{i=1}^{n} sum_{j=1}^{m} epsilon(gcd(i,j))ij ]

根据(epsilon=mu * I)

[=sum_{i=1}^{n} sum_{j=1}^{m} ij sum_{d|gcd(i,j)} mu (d) ]

枚举(d)(交换枚举量)

[=sum_{d=1}^{min(n,m)} sum_{i=1}^{lfloor frac{n}{d} floor} sum_{j=1}^{lfloor frac{m}{d} floor} mu(d) ij d^2 ]

[=sum_{d=1}^{min(n,m)} mu(d) d^2 sum_{i=1}^{lfloor frac{n}{d} floor} sum_{j=1}^{lfloor frac{m}{d} floor} ij ]

我们再把后面这个玩意提出来

[h(n,m)=sum_{i=1}^n sum_{j=1}^m ij ]

[=(1+2+cdots +n) imes (1+2+cdots +m) ]

[=frac{n imes (n+1)}{2} imes frac{m imes (m+1)}{2} ]

所以(h(n,m))可以(O(1))求解
由此我们可以得到

[S(n,m)=sum_{d=1}^{min(n,m)} mu(d) d^2 ;;h(lfloor frac{n}{d} floor,lfloor frac{m}{d} floor) ]

[Ans=sum_{d=1}^{min(n,m)} d;;S(lfloor frac{n}{d} floor,lfloor frac{m}{d} floor) ]

这样的复杂度是多少呢?
首先我们枚举(d),然后计算(S(lfloor frac{n}{d} floor,lfloor frac{m}{d} floor))
由于算(S(n,m))(O(min(n,m)))
所以最终的复杂度大约是(O(frac{n}{1}+frac{n}{2}+cdots +frac{n}{n})=O(n;log;n))
但是(10^7)貌似不太行啊。
所以就要用到整除分块,用(O(sqrt n))分别计算:

[S(n,m)=sum_{d=1}^{min(n,m)} mu(d) d^2 ;;h(lfloor frac{n}{d} floor,lfloor frac{m}{d} floor) ]

[sum_{d=1}^{min(n,m)} d;;S(lfloor frac{n}{d} floor,lfloor frac{m}{d} floor) ]

即可
时间复杂度:(O(n))
题目地址: https://www.luogu.com.cn/problem/P1829
(Code:)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=10000010,mod=20101009;
int n,m,phi[N],mu[N],prime[N],cnt,res,st[N],sum[N];
void qwq(int n)
{
    phi[1]=1;mu[1]=1;
    for(int i=2;i<=n;i++)
    {
        if(!st[i])
	{
	    prime[++cnt]=i;
	    phi[i]=i-1;
            mu[i]=-1; 
	}
	for(int j=1;j<=cnt&&i*prime[j]<=n;j++)
	{
	    st[i*prime[j]]=1;
	    if(i%prime[j])
	    {
	    	phi[i*prime[j]]=phi[i]*phi[prime[j]];
	        mu[i*prime[j]]=mu[i]*mu[prime[j]];
	    } 
	    else
	    {
	        phi[i*prime[j]]=phi[i]*prime[j];
		mu[i*prime[j]]=0;
	        break;
	    }
	}
    }
}
int h(int n,int m)
{
    return (1LL*n*(n+1)/2%mod)*(1LL*m*(m+1)/2%mod)%mod;
}
int S(int n,int m)
{
    int ans=0;
    for(int l=1,r;l<=min(n,m);l=r+1)
    {
	r=min(n/(n/l),m/(m/l));
	ans=(ans+1LL*(sum[r]+mod-sum[l-1])%mod*h(n/l,m/l)%mod)%mod;
    }
    return ans;
}
int main()
{
    scanf("%d%d",&n,&m);
    qwq(min(n,m));
    for(int d=1;d<=min(n,m);d++)
    {
	sum[d]=(sum[d-1]+1LL*(mu[d]+mod)*d%mod*d%mod)%mod;
    }
    for(int l=1,r;l<=n;l=r+1)
    {
	if(n/l==0||m/l==0)break;
	r=min(n/(n/l),m/(m/l));
	res=(res+1LL*(r-l+1)*(l+r)/2%mod*S(n/l,m/l)%mod)%mod;
    }
    printf("%d",res);
    return 0;
} 

(;)
(;)

Problem 3

求:(1leq xleq n,1leq yleq m)(gcd(x,y))为质数的((x,y))有多少对
(T)组询问。(1leq n,m leq 10^7,Tleq 10^4)
即:

[sum_{i=1}^n sum_{j=1}^m [gcd(i,j)=prime] ]

推导:
枚举prime

[=sum_{k=1}^{cnt} sum_{i=1}^n sum_{j=1}^m [gcd(i,j)=prim_k] ]

常规套路,消去一个(prim_k)

[=sum_{k=1}^{cnt} sum_{i=1}^{lfloor frac{n}{prim_k} floor} sum_{j=1}^{lfloor frac{m}{prim_k} floor} [gcd(i,j)=1] ]

[=sum_{k=1}^{cnt} sum_{i=1}^{lfloor frac{n}{prim_k} floor} sum_{j=1}^{lfloor frac{m}{prim_k} floor} epsilon(gcd(i,j)) ]

[=sum_{k=1}^{cnt} sum_{i=1}^{lfloor frac{n}{prim_k} floor} sum_{j=1}^{lfloor frac{m}{prim_k} floor} sum_{d|gcd(i,j)} mu (d) ]

[=sum_{d=1}^{min(lfloor frac{n}{prim_k} floor,lfloor frac{m}{prim_k} floor)}sum_{k=1}^{cnt} sum_{i=1}^{lfloor frac{lfloor frac{n}{prim_k} floor}{d} floor} sum_{j=1}^{lfloor frac{lfloor frac{m}{prim_k} floor}{d} floor} mu (d) ]

(lfloor frac{lfloor frac{a}{b} floor}{c} floor=lfloor frac{a}{bc} floor)

[=sum_{d=1}^{min(lfloor frac{n}{prim_k} floor,lfloor frac{m}{prim_k} floor)}sum_{k=1}^{cnt} sum_{i=1}^{lfloor frac{n}{prim_k d} floor} sum_{j=1}^{lfloor frac{m}{prim_k d} floor} mu (d) ]

[=sum_{d=1}^{min(lfloor frac{n}{prim_k} floor,lfloor frac{m}{prim_k} floor)}sum_{k=1}^{cnt} lfloor frac{n}{prim_k d} floor imes lfloor frac{m}{prim_k d} floor imesmu (d) ]

如果简单的枚举(prime),然后你就开心地发现你(TLE)了。
有一个十分巧妙的方法:
(T=prim_k d)
然后我们枚举(T),即可得到下面的式子:

[sum_{T=1}^{min(n,m)} lfloor frac{n}{T} floor imes lfloor frac{m}{T} floor imes sum_{prim_k|T} mu (frac{T}{prim_k}) ]

然后你发现:(sum_{prim_k|T} mu (frac{T}{prim_k}))这个东西是可以预处理的。
即:枚举每个质数的倍数,把(mu)加到倍数里面

for(int i=1;i<=cnt;i++)
{
    for(int j=1;prime[i]*j<=N-10;j++)
    {
        cur[prime[i]*j]+=mu[j];
    }
}

所以我们对于每组询问,用上述方法,再加上整除分块的优化,即可(O(sqrt n))求出答案
时间复杂度:(O(T imes sqrt n))
(Code:)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int N=10000010;
typedef long long LL;
int n,m,T,prime[N],cnt,mu[N],st[N],sum[N],cur[N];
int sumcur[N];
void qwq(int n)
{
	mu[1]=1;
	for(int i=2;i<=n;i++)
	{
		if(!st[i])
		{
			prime[++cnt]=i;
			mu[i]=-1;
		}
		for(int j=1;j<=cnt&&i*prime[j]<=n;j++)
		{
			st[i*prime[j]]=1;
			if(i%prime[j])
			{
				mu[i*prime[j]]=mu[i]*mu[prime[j]];
			}
			else
			{
				mu[i*prime[j]]=0;
				break;
			}
		}
	}
	for(int i=1;i<=n;i++)sum[i]=sum[i-1]+mu[i];
}
LL Query(int n,int m)
{
	LL res=0;
	for(int S=1,r;S<=min(n,m);S=r+1)
	{
		if(n/S==0||m/S==0)break;
		r=min(n/(n/S),m/(m/S));
		res=res+1LL*(n/S)*(m/S)*(sumcur[r]-sumcur[S-1]); 
	}
	return res;
}
int main()
{
	scanf("%d",&T);
	qwq(N-10);
	for(int i=1;i<=cnt;i++)
	{
		for(int j=1;prime[i]*j<=N-10;j++)
		{
			cur[prime[i]*j]+=mu[j];
		}
	}
	for(int i=1;i<=N-10;i++)sumcur[i]=sumcur[i-1]+cur[i];
	while(T--)
	{
		scanf("%d%d",&n,&m);
		printf("%lld
",Query(n,m));
	}
	return 0;
}

(;)
题目地址: https://www.luogu.com.cn/problem/P2257

原文地址:https://www.cnblogs.com/czyty114/p/12720508.html