莫比乌斯反演学习笔记

1. 整除分块

1.1. 简述

例题:求 i=1nni

这个东西就是指将 1n 的所有数按 ni 的值进行分块,数值大的在右边

性质1:分块的个数 2n

证明:当 in 时,必然至多 n 种取值

i>n 时,nin,所以只有 n 种取值

性质2i 所在快的右端点是 nni

证明:i 所在块的值为 ni,记为 k,必然存在 kni

则有 nknni=i=i

所以 imax=nk=nni

所以,在求解如上例题时,不必算出所有的值,只要知道左右端点即可

1.2. 例题

1.2.1. 约数和

板子,求出左右端点然后等差数列求和即可

点击查看代码
#include<cstdio>
#define ll long long
using namespace std;
ll get(ll x)
{
	ll res=0;
	for(ll i=1;i<=x;i++)
	{
		ll c=x/i,j,sum;
		j=x/c;
		sum=(i+j)*(j-i+1)/2;
		res+=sum*c;
		i=j;
	}
	return res;
}
int main()
{
	ll x,y;
	scanf("%lld%lld",&x,&y);
	printf("%lld",get(y)-get(x-1));
	return 0;
}

1.2.2. [CQOI2007] 余数求和

可以把余数转化为 i=1nkki,然后同上

点击查看代码
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
ll n,k,ans;
int main()
{
	scanf("%lld%lld",&n,&k);
	for(ll i=1;i<=min(n,k);i++)
	{
		ll c=k/i,j,sum;
		j=k/c;
		j=min(j,n);
		sum=(i+j)*(j-i+1)/2;
		ans+=sum*c;
		i=j;
	}
	printf("%lld",n*k-ans);
	return 0;
}

2. 狄利克雷卷积

数列 a={a1,a2,a3} 的狄利克雷生成函数是 f(x)=n=1annx

乘法运算

i=1aiixj=1bjjx=(a11x+a22x+a33x+)(b11x+b22x+b33x+)=a1b11x+a1b2+a2b12x+a1b3+a3b13x+=n=11nxd|nadbdn

积性函数f(1)=1,当 gcd(a,b)=1 时,有 f(ab)=f(a)f(b)

欧拉函数和莫比乌斯函数都是积性函数

2.1. 欧拉函数

定义φ(n)=i=1n[gcd(i,n)=1]

性质d|nφ(d)=n

证明:

观察以 12 为分母的真分数:

012,112,212,312,412,512,612,712,812,912,1012,1112

化简并按分母分组得:

01,12,13,23,14,34,16,56,112,512,712,1112

发现分母都是 12 的约数,个数为 φ(i)

推广到 n,每个分数在化成最简分数后,分母都是 n 的约数,而且分子包含了每个与分母互质的数

2.2. 莫比乌斯函数

定义

μ(n)={1n=1(1)sn=p1p2ps0other.

性质d|nμ(d)=[n=1]

证明:

n=1 时,显然

n1 时,n=p1a1p2a2psas

n=p1p2ps

d|nμ(d)=d|nμ(d)=(s0)+(1)(s1)+(1)2(s2)++(1)s(ss)=(1+(1))s=0

  • 莫比乌斯函数和欧拉函数的关系:d|nμ(d)nd=φ(n)

证明:

n=1 显然

n>1 时,n=p1a1p2a2psas

n=p1p2ps

d|nμ(d)nd=nd|nμ(d)d=n(1(1p1+1p2++1ps)+(1p1p2++1ps1ps))=n(11p1)(11p2)(11ps)=φ(n)

2.3. 狄利克雷卷积

定义 f(x),g(x) 为积性函数

(fg)(n)=d|nf(d)g(nd)=d|nf(nd)g(d)

规律:满足交换律,结合律,分配律

常用函数

  1. 元函数:ε(n)=[n=1]
  2. 常数函数:1(n)=1
  3. 恒等函数:id(n)=n

常用卷积关系

d|nμ(d)=[n=1]μ1=ε

d|nφ(d)=nφ1=id

d|nμ(d)nd=φ(n)φid=μ

fε=f

f1=f

3. 和式的变换

变换规则:1.结合律 2.交换律 3.分配律

变换技术

  • 替换条件式:i=1nj=1md|gcd(i,j)d=i=1nj=1md=1n[d|i][d|j]d
  • 替换指标变量:i=1nj=1m[gcd(i,j)=k]=ik=1njk=1m[gcd(ik,jk)=k]
  • 交换求和次序:i=1nj=1mA(i)B(j)=j=1mi=1nA(i)B(j)
  • 分离变量:i=1nj=1mA(i)B(j)=i=1nA(i)j=1mB(j)

相关练习

YY的GCD

https://www.gxyzoj.com/d/gxyznoi/p/P5

显然的,原题可以转化为:

k=1ni=1nkj=1mk[gcd(i,j)=1][kprime]=k=1ni=1nkj=1mkd|gcd(i,j)μ(d)[kprime]=k=1ni=1nkj=1mkd=1nkμ(d)[d|i][d|j][kprime]=k=1nd=1nkμ(d)i=1nk[d|i]j=1mk[d|j][kprime]=k=1nd=1nkμ(d)nkdmkd[kprime]

但是这样无法计算,记 T=kd

=k=1nTk=1nkμ(Tk)nTmT[kprime]=k=1nT=1nμ(Tk)nTmT[kprime]=T=1nnTmTkprimeμ(Tk)

预处理一下莫比乌斯函数即可

点击查看代码
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const int N=1e7;
int T,n,m,vis[N+5],p[N+5],mu[N+5],cnt,f[N+5];
void init()
{
	mu[1]=1;
	for(int i=2;i<=N;i++)
	{
		if(!vis[i])
		{
			p[++cnt]=i;
			mu[i]=-1;
		}
		for(int j=1;i*p[j]<=N;j++)
		{
			vis[i*p[j]]=1;
			if(i%p[j]==0) break;
			mu[i*p[j]]=-mu[i];
		}
	}
	for(int i=1;i<=cnt;i++)
	{
		for(int j=p[i];j<=N;j+=p[i])
		{
			f[j]+=mu[j/p[i]];
		}
	}
	for(int i=1;i<=N;i++)
	{
		f[i]+=f[i-1];
	}
}
ll clac(int n,int m)
{
	ll ans=0;
	if(n>m) swap(n,m);
	for(int i=1;i<=n;i++)
	{
		int j=min(n/(n/i),m/(m/i));
		ans+=1ll*(f[j]-f[i-1])*(n/i)*(m/i);
		i=j;
	}
	return ans;
}
int main()
{
	init();
	scanf("%d",&T);
	while(T--)
	{
		scanf("%d%d",&n,&m);
		printf("%lld\n",clac(n,m));
	}
	return 0;
}

[SDOI2015] 约数个数和

有一个公式 d(ij)=x|iy|j[gcd(i,j)=1]

经过推式子和化简为求 d=1nx=1ndndxy=1ydydy

做两次整除分块即可

点击查看代码
#include<cstdio>
#include<algorithm>
#define ll long long
using namespace std;
const int N=5e4;
int T,n,m,vis[N+5],p[N+5],mu[N+5],sum[N+5],cnt;
ll f[N+5];
void init()
{
	mu[1]=1;
	for(int i=2;i<=N;i++)
	{
		if(!vis[i])
		{
			p[++cnt]=i;
			mu[i]=-1;
		}
		for(int j=1;i*p[j]<=N;j++)
		{
			vis[i*p[j]]=1;
			if(i%p[j]==0) break;
			mu[i*p[j]]=-mu[i];
		}
	}
	for(int i=1;i<=N;i++)
	{
		sum[i]=sum[i-1]+mu[i];
		for(int l=1;l<=i;l++)
		{
			int r=i/(i/l);
			f[i]+=1ll*(r-l+1)*(i/l);
			l=r;
		}
	}
}
ll clac(int n,int m)
{
	if(n>m) swap(n,m);
	ll ans=0;
	for(int i=1;i<=n;i++)
	{
		int j=min(n/(n/i),m/(m/i));
		ans+=(sum[j]-sum[i-1])*f[n/i]*f[m/i];
		i=j;
	}
	return ans;
}
int main()
{
	scanf("%d",&T);
	init();
	while(T--)
	{
		scanf("%d%d",&n,&m);
		printf("%lld\n",clac(n,m));
	}
	return 0;
}

3. 莫比乌斯反演

g(n)=d|nf(d)

f(n)=d|ng(nd)μ(d)

证明:条件等价于 g=f1,则 μg=f1μ=fε=f

posted @   wangsiqi2010916  阅读(14)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
点击右上角即可分享
微信分享提示