学习笔记——莫比乌斯反演

前言#

时隔一年,学了点多项式基础,然后来搞搞数论。学一下颓柿子。

数论分块#

是用莫反解决问题的基础。

形式:如果有式子 i=1ng(ni) 需要求值,我们能在 O(n) 的复杂度内求出上面这个式子的值。即需要求的东西中需要有带整除的值,所以也叫整除分块。

考虑到当 n 很大的时候,我们这个 ni 的取值是非常少的。可以证明取值不超过 2n 个。

Proof

in,那么就算每个 i 都有一个不同的 ni,那总数也不超过 n 个。

in,那么有 ninin,所以也不超过 sqrtn 个。

综上,这样的取值不超过 2n 个。

接下来我们需要一个性质:xab=xab

证明略。

然后就有如下结论:对于每个 ni 相等的块,其左端点为 l 的话,右端点就是 nnl

Proof

k=ni,有 nini

nknni=i。所以最大的 i 就是 nk=nni

这样一来,代码就很好写了。

Code
void solve(){
	ll n;cin>>n;
	ll ans=0;
	for(ll l=1,r;l<=n;l=r+1){
		r=n/(n/l);ans+=(r-l+1)*(n/l);
	}cout<<ans<<'\n';
}
int main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	int T;for(cin>>T;T--;)solve();
	return 0;
}
Code
int main()
{
	ll n,k,ans;
	scanf("%lld%lld",&n,&k);ans=n*k;
	for(ll l=1,r;l<=n;l=r+1){
		if(k/l) r=min(k/(k/l),n);else r=n;
		ans-=(l+r)*(r-l+1)/2*(k/l);
	}printf("%lld\n",ans);
}

以及一个显然的结论:

d|nf(d)=d|nf(nd)

前置知识#

你需要会素数筛(好歹是线性筛吧),然后唯一分解定理。

然后是调和级数求和是 nlogn 也得知道。

数论函数#

定义:若对于 ab,有 f(ab)=f(a)f(b),则 f(x) 为积性函数。

单位函数#

ϵ(x)=[x=1]

任何函数卷积上这个函数都是那个函数本身。单位函数是积性的。

除数函数#

σk(x)=d|ndk

σ0(x)x 的约数个数,σ1(x) 为约数和,简称 σ(x)。除数函数也是积性的。

欧拉函数#

内容比较多,主要是关于欧拉定理和欧拉筛的,φ(x) 表示小于 x 的与 x 互质的数的个数。

φ(x)=xi=1s(11pi)

其中 pi 表示 x 的第 i 个质因子。当然也可以用欧拉筛出欧拉函数。

幂函数#

Idk(x)=xk

狄利克雷卷积#

一种特殊的因数卷积。

h(x)=d|nf(d)g(nd)

f(x)g(x) 的狄利克雷卷积,记做 h=fg

性质:满足结合律,并且如果 f,g 都是积性函数,那么 fg 也是积性函数。

一些常见的卷积:μ1=ϵ,Id=φ1

也就是:

[x=1]=d|xμ(d)

x=d|xφ(d)

莫比乌斯函数#

μ(x)={0x=k2a1n=1(1)kx=p1p2p3pk

这东西由于也是积性的,可以用线性筛求。

莫比乌斯反演#

g=f1,则 gf 的莫比乌斯变换。

那么 f 就是 g 的莫比乌斯逆变换。

莫比乌斯反演定理指出:g=f1f=gμ

一些例题#

题单

题单中指出了莫比乌斯反演的三种形式,也就是最常见的三种。


Case1:

x=1ny=1m[gcd(x,y)=1]=x=1ny=1md|gcd(x,y)μ(d)=x=1ny=1md|xd|yμ(d)=d=1min(n,m)μ(d)x=1ny=1m[d|x][d|y]=d=1min(n,m)μ(d)ndmd

然后你整除分块搞一下就可以 O(n) 求了。


Case2:

x=1ny=1mgcd(x,y)=x=1ny=1md|gcd(x,y)φ(d)

然后和上面那个同理,最后

x=1ny=1mgcd(x,y)=d=1min(n,m)φ(d)ndmd


Case3:

x=1ny=1mf(gcd(x,y))=d=1min(n,m)f(d)x=1ny=1m[gcd(x,y)=d]=d=1min(n,m)f(d)x=1ndy=1md[gcd(x,y)=1]=d=1min(n,m)f(d)k=1min(nd,md)μ(k)ndkmdk=d=1min(n,m)f(d)k=1min(nd,md)μ(k)nkdmkd

接着令 T=kd,则有:

x=1ny=1mf(gcd(x,y))=T=1min(n,m)nTmTd|Tf(d)μ(Td)

P2568 GCD#

本题要求:

pPx=1npy=1np[gcd(x,y)=1]=pPx=1npμ(x)npx2

然后暴力枚举直接做就好了。

Code
const int MAXN=1e7+10;
int mu[MAXN],pr[MAXN],p[MAXN],cnt,n;
void init(){
	p[1]=1;mu[1]=1;
	rep(i,2,n){
		if(!p[i]) pr[++cnt]=i,mu[i]=-1;
		for(int j=1;j<=cnt&&i*pr[j]<=n;j++){
			p[i*pr[j]]=1;
			if(i%pr[j]){
				mu[i*pr[j]]=-mu[i];
			}else{mu[i*pr[j]]=0;break;}
		}
	}
}
int pre[MAXN];
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	cin>>n;init();
	rep(i,1,n) pre[i]=pre[i-1]+mu[i];
	int ans=0;
	rep(i,1,cnt){
		int m=n/pr[i],cur=0;
		for(int l=1,r;l<=m;l=r+1){
			r=m/(m/l);cur+=(pre[r]-pre[l-1])*(m/l)*(m/l);
		}ans+=cur;
	}cout<<ans<<'\n';
	return 0;
}

P1891 疯狂 LCM#

题目要求:

i=1nlcm(i,n)=ni=1nigcd(i,n)=nd|ni=1nid[gcd(i,n)=d]=nd|ni=1ndi[gcd(i,nd)=1]=nd|nφ(nd)×nd2=nd|nφ(d)×d2=n2d|nφ(d)×d

f(x)=d|xφ(d)×d,这是个积性函数,可以筛出来。

Code
const int MAXN=1e6+10;
int p[MAXN],pr[MAXN],cnt;
ll f[MAXN];
void init(){
	f[1]=1;p[1]=1;
	rep(i,2,MAXN-10){
		if(!p[i]){pr[++cnt]=i,f[i]=1ll*i*(i-1)+1;}
		for(int j=1;j<=cnt&&i*pr[j]<=MAXN-10;j++){
			p[i*pr[j]]=1;
			if(i%pr[j]) f[i*pr[j]]=f[i]*f[pr[j]];
			else{f[i*pr[j]]=f[i]+(f[i]-f[i/pr[j]])*pr[j]*pr[j];break;}
		}
	}
}
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	init();
	int T;for(cin>>T;T--;){
		int n;cin>>n;
		cout<<1ll*(n*f[n]+n)/2<<'\n';
	}
	return 0;
}

SP21615 NAJPWG - Playing with GCD#

题目要求:

i=1nj=in[gcd(i,j)>1]=i=1nj=1i[gcd(i,j)1]=i=1niφ(i)

直接预处理就好了。

Code
const int MAXN=1e5+10;
int p[MAXN],pr[MAXN],phi[MAXN],cnt;
int ans[MAXN];
void init(){
	phi[1]=1;p[1]=1;
	rep(i,2,MAXN-10){
		if(!p[i]) pr[++cnt]=i,phi[i]=i-1;
		for(int j=1;j<=cnt&&i*pr[j]<=MAXN-10;j++){
			p[i*pr[j]]=1;
			if(i%pr[j]) phi[i*pr[j]]=phi[i]*phi[pr[j]];
			else{phi[i*pr[j]]=phi[i]*pr[j];break;}
		}
	}rep(i,1,MAXN-10) ans[i]=ans[i-1]+i-phi[i];
}
void solve(int Cas){
	int n;
	cin>>n;
	cout<<"Case "<<Cas<<": "<<ans[n]<<'\n';
}
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);cout.tie(0);
	init();
	int T;cin>>T;
	rep(_,1,T) solve(_);
	return 0;
}

AT5310 [ABC162E] Sum of gcd of Tuples (Hard)#

posted @   ZCETHAN  阅读(94)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示
主题色彩