数论函数小计

1.基础

数论函数

  • 定义: 数论函数,就是值域为整数(陪域为复数)的函数

狄利克雷卷积

两个数论函数狄利克雷卷积是一个新的函数

比如 f(n),g(n) 它们的卷积就是 fg

怎么卷呢?

定义: (fg)(n)=d|nf(n)g(n/d)

举个例子:

(fg)(12)=f(1)g(12)+f(2)g(6)+f(3)g(4)f(12)g(1)

狄利克雷卷积满足交换律和结合律:

fg = gf

fgh=f(gh)

基本函数

  • 恒等函数:I(n) I(n)=1 无论n是什么,它永远等于1
  • 元函数:e(n) e(n)=[n=1] 只有n=1时为1,其余为0 满足ef=f
  • 编号函数:idx(n)=nx

完全积性函数

  • 定义:对于完全积性函数 I 有任意整数a,b使I(a)I(B)=I(ab)

I,e,id函数都是完全积性函数

积性函数

  • 定义:对于积性函数f(a,b)==1f(a)f(b)=f(ab)

完全积性函数是积性函数

后面的 φ(n)μ(n)都是积性函数

性质:

  • 对于任意积性函数 有 F(1)=1

证明:因为F(1)F(1)=F(1) 所以F(1)=1F(1)=0这个积性函数无意义

  • 两个积性函数的卷积还是积性函数
  • 积性函数的逆元也是积性函数

定义:满足gf=egf互逆

2.莫比乌斯函数

如果我们知道f 可以通过 F=If (I是恒等函数) 求出F

那如果我们知道 F 怎么求 f? 两边同时乘上I1就行

I1就是莫比乌斯函数 μ

根据I是积性函数 所以μ也是积性函数

那么μ怎么算?

首先

  • μ(1)=1

从素数开始考虑 设当前素数为k

根据e(k)=d|nμ(n)I(n/d) k还是素数

所以e(k)=μ(1)I(k)+μ(k)I(1)

所以0=1+f(k)

所以f(k)=1

然后再想素数的多次方
e(kx)=μ(1)+μ(k)+μ(k2)+μ(k3)μ(kx1)

k=2带入 0=11+μ(k2)

同理可得 μ(kx)=0

根据积性函数的性质,容易得到μ的定义:

  • 0x含有平方因子
  • (1)k kx的质因子个数

莫比乌斯反演

怎么反演呢?

当有这样的问题:

i=1nj=1m[(i,j)==1]

[(i,j)==1]d|nμ(d)

这样就能转化了

为什么?这其实就是μ卷积呗 只有卷1才能为1

例题

链接 here

现在有这样的问题:
i=1nj=1m[(i,j)==1]

带入反演
i=1nj=1md|i,d|jμ(d)

往前提d=1min(n,m)μ(d)i=1n/dj=1m/d

再化简d=1min(n,m)μ(d)(n/d)(m/d)

这样就是O(n)

整除分块一下就是O(n)

具体实现

线性筛

线性筛可以做到O(n)处理出n以内的μ

特别地,如果单独求一个μ,可以用n枚举因数的做法

怎么线性筛呢?分类讨论

  • primej|i时 说明primeji已经出现了重复因子 只需令μ(primeji)=0
  • 否则 可以根据积性函数的性质转移即可

code

void init()
{
	p[1]=1;
	mul[1]=1;
	for(int i=2;i<=MAXN-3;i++)
	{
		if(!p[i])
		{
			q[++l]=i;
			mul[i]=-1;
		}
		for(int j=1;j<=l&&i*q[j]<=MAXN-3;j++)
			if(i%q[j]==0)
			{
				p[i*q[j]]=1;
				mul[i*q[j]]=0;
				break;
			}
			else 
			{
				p[i*q[j]]=1;
				mul[i*q[j]]=mul[i]*mul[q[j]];
			}
	}
}

整除分块

观察公式d=1min(n,m)μ(d)(n/d)(m/d)

发现一定存在一段(n/d)(m/d)是连续的d

这段重复算会浪费很多时间

把这些相同的分成一块块 加上前缀和一起算可以优化成O(n)

每次一块一块枚举即可

练习题:T1T2

这些芝士结合一下就是例题的解

code

#include<bits/stdc++.h>
#define ll long long
#define MAXN 50005
using namespace std;
int g,mul[MAXN],p[MAXN];
int q[MAXN],l;
ll n,m,d,ans;
void init()
{
	p[1]=1;
	mul[1]=1;
	for(int i=2;i<=MAXN-3;i++)
	{
		if(!p[i])
		{
			q[++l]=i;
			mul[i]=-1;
		}
		for(int j=1;j<=l&&i*q[j]<=MAXN-3;j++)
			if(i%q[j]==0)
			{
				p[i*q[j]]=1;
				mul[i*q[j]]=0;
				break;
			}
			else 
			{
				p[i*q[j]]=1;
				mul[i*q[j]]=mul[i]*mul[q[j]];
			}
	}
	for(int i=2;i<=MAXN-3;i++)
		mul[i]+=mul[i-1];
}
void solve()
{
	for(int l=1,r=0;l<=min(n,m);l=r+1)
	{
		r=min(n/(n/l),m/(m/l));
		ans+=(n/l)*(m/l)*(mul[r]-mul[l-1]);
	}
}
int main()
{
	init();
	scanf("%d",&g);
	while(g--)
	{
		ans=0;
		scanf("%lld%lld%lld",&n,&m,&d);
		n/=d,m/=d;
		solve();
		printf("%lld\n",ans);
	}
	return 0;
}

例题2

链接:here

这道题题目让我们求i=1nj=1m(i,j)是质数的个数

首先 将题目转化成

kprimei=1nj=1m(i,j)=k

=kprimei=1n/kj=1m/k(i,j)=1

=kprimei=1n/kj=1m/kd|i,d|jμ(d)

前提μ

=kprimed=1nμ(d)i=1n/k,d|nj=1m/k,d|m

=kprimed=1nμ(d)(n/kd)(m/kd)

如果此时直接按这个做时间复杂度为O(Tnnnm)

过不了 当柿子无法优化时可以用另一个方法

令T=kd

=kprimed=1nμ(T/k)(n/T)(m/T)

=T=1n(n/T)(m/T)kprime,k|Tμ(T/k)

然后发现后面这$\sum\limits_{k\in prime ,k|T}\mu(T/k) O(nloglogn)$埃氏筛预处理

前面T=1n(n/T)(m/T)能整除优化

=T=1n(n/T)(m/T)sum(T)

因此 时间复杂度降至O(nloglogn+Tn) 能通过本题

Code

#include<bits/stdc++.h>
#define ll long long
#define MAXN 10000005
using namespace std;
int n,g,m;
int q[MAXN],l;
int p[MAXN],mul[MAXN],sum[MAXN];
ll ans;
void init()
{
	mul[1]=p[1]=1;
	for(int i=2;i<=MAXN-3;i++)
	{
		if(!p[i])
		{
			mul[i]=-1;
			q[++l]=i;
		}
		for(int j=1;j<=l&&q[j]*i<=MAXN-3;j++)
		{
			p[q[j]*i]=1;
			if(i%q[j]==0)
			{
				mul[q[j]*i]=0;
				break;
			}
			else mul[q[j]*i]=mul[q[j]]*mul[i];
		}
	}
	for(int i=1;i<=l;i++)
		for(int j=1;j*q[i]<=MAXN-3;j++)
			sum[j*q[i]]+=mul[j];
	for(int i=2;i<=MAXN-3;i++)
		sum[i]+=sum[i-1];
}
ll solve(int n,int m)
{
	ll s=0;
	for(int l=1,r=0;l<=min(n,m);l=r+1)
	{
		r=min(n/(n/l),m/(m/l));
		s+=1ll*(n/l)*(m/l)*(sum[r]-sum[l-1]);
	}
	return s;
}
int main()
{
	init();
	scanf("%d",&g);
	while(g--)
	{
		scanf("%d%d",&n,&m);
		printf("%lld\n",solve(n,m));
	}
	return 0;
}

3 欧拉函数 φ

定义φ(x)表示1x中与x互质的数的个数

推导 借助容斥

p1,p2,p3,pk(pix)prime

ϕ(x)=xx/p1x/p2x/p3+x/p1p2+x/p2p3

=x(11/p11/p21/p3+1/p1p2+1/p1p3)

上面左边的那一坨根据观察可以化简为

=x(11/p1)(11/p2)(11/p3)

=xp1/(p11)p2/(p21)p3/(p31)

借助这个东西我们可以通过O(x)的时间复杂度分解质因数得出φ(x)

可是如果要求1n这些φ(i)咋办?

其实φ是积性函数 证明

(n,m)=1

φ(n)φ(m)=i=1n((n,i)=1)j=1m((m,j)=1)

然后自行取百度吧后面我看不懂

最终得=i=1nm((nm,i)=1)=φ(nm)

口胡结束

其实也可以感性理解一下

a1,a2,a3ax(ain)prime

b1,b2,b3by(bim)prime

φ(n)=n(11/a1)(11/a2)(11/a3)(11/ax)

φ(m)=m(11/b1)(11/b2)(11/b3)(11/by)

根据n,m互质 可知 nmn,m的所有质因子

因此 φ(n)φ(m)=nm(11/a1)(11/a2)(11/a3)

(11/ax)(11/b1)(11/b2)(11/b3)(11/by)=φ(nm)
二次口胡结束

好了你已经知道φ(x)是积性函数了 现在你只需要使用线性筛就可以了

怎么筛呢 还是分类

  • 当筛的时候 imodprimej=0时 说明iprimej中已经相同质因子 所以i已经包含iprimej所有质因子 因此φ(iprimej)=φ(i)primej 这个证明拆公式就行

  • 否则(i,primej)=1 直接使用积性函数的性质即可

Code

void init()
{
	phi[1]=p[1]=1;
	for(int i=2;i<=n;i++)
	{
		if(!p[i])
		{
			phi[i]=i-1;
			q[++l]=i;
		}
		for(int j=1;j<=l&&q[j]*i<=n;j++)
		{
			p[q[j]*i]=1;
			if(i%q[j]==0)
			{
				phi[q[j]*i]=phi[i]*q[j];
				break;
			}
			else phi[q[j]*i]=phi[q[j]]*phi[i];
		}
	}
}

例题

链接:here
题目让我们求

i=1nj=1n(i,j)

枚举d i=1nj=1nd|i,d|jd((i,j)=d)

d的枚举提前d=1ndi=1nj=1n(i,j)=d

优化 d=1ndi=1n/dj=1n/d(i,j)=1

转化
d=1nd((2i=1n/dj=1i(i,j)=1)1)

定睛一看 j=1i(i,j)=1不就φ(i)吗 直接优化原柿

转化
d=1nd((2i=1n/dφ(i))1)

发现后面的柿子可以前缀和优化 然后前面跑一遍可以O(n)过了本题

Code

#include<bits/stdc++.h>
#define ll long long
#define MAXN 100005
using namespace std;
int n;
int q[MAXN],l;
int p[MAXN],phi[MAXN];
ll ans,sum[MAXN];
void init()
{
	phi[1]=p[1]=1;
	for(int i=2;i<=n;i++)
	{
		if(!p[i])
		{
			phi[i]=i-1;
			q[++l]=i;
		}
		for(int j=1;j<=l&&q[j]*i<=n;j++)
		{
			p[q[j]*i]=1;
			if(i%q[j]==0)
			{
				phi[q[j]*i]=phi[i]*q[j];
				break;
			}
			else phi[q[j]*i]=phi[q[j]]*phi[i];
		}
	}
	for(int i=1;i<=n;i++)
		sum[i]=phi[i]+sum[i-1];
}
int main()
{
	scanf("%d",&n);
	init();
	for(int i=1;i<=n;i++)
		ans+=i*(2*sum[n/i]-1);
	printf("%lld",ans);
	return 0;
}

欧拉反演

首先要知道一条理论:

d|nφ(d)=n

证明:

我们把1n分成

1n,2n,3nnn,

其中 约分后分母相同为一类

同分母的数的个数为ϕ(x)

举个例子 n=10

那么分母为10的数很明显是与10互质的 就是φ(10)

分母为5的数很明显是 110去掉一个因数210互质的数个数

那么其实可以转化成 155互质的数个数 为φ(5)

1,2同理 原柿得证

这种方法叫做映射法

根据这个性质可以得到:

φI=id

我们又知道 I=μ1

所以φ=idμ

例题

还是

i=1nj=1n(i,j)

但是有了T(T104)组数据 我们如果直接O(nT)搞肯定T

根据我们学习的欧拉反演 我们可以变换原柿

=i=1nj=1nd|i,d|jφ(d)

前提d =d=1ni=1,i|dnj=1,j|dnφ(d)

然后发现柿子与i,j无关 可以优化为=d=1n(n/d)(n/d)φ(d)

合并=d=1n(n/d)2φ(d)

然后整除分块可以优化成O(n)

Code

#include<bits/stdc++.h>
#define ll long long
#define MAXN 100005
using namespace std;
int n;
int q[MAXN],l;
int p[MAXN],phi[MAXN];
ll ans,sum[MAXN];
void init()
{
	phi[1]=p[1]=1;
	for(int i=2;i<=n;i++)
	{
		if(!p[i])
		{
			phi[i]=i-1;
			q[++l]=i;
		}
		for(int j=1;j<=l&&q[j]*i<=n;j++)
		{
			p[q[j]*i]=1;
			if(i%q[j]==0)
			{
				phi[q[j]*i]=phi[i]*q[j];
				break;
			}
			else phi[q[j]*i]=phi[q[j]]*phi[i];
		}
	}
	for(int i=1;i<=n;i++)
		sum[i]=phi[i]+sum[i-1];
}
ll solve(int n)
{
	ll s=0;
	for(int l=1,r;l<=n;l=r+1)
	{
		r=n/(n/l);
		s+=1ll*(n/l)*(n/l)*(sum[r]-sum[l-1]);
	}
	return s;
}
int main()
{
	scanf("%d",&n);
	init();
	printf("%lld",solve(n));
	return 0;
}

练习题:here

posted @   g1ove  阅读(25)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示