欧拉函数、莫比乌斯函数、杜教筛

积性函数

1、积性函数:任意互素的两个数m、n,满足f(mn)=f(m)f(n)
常见积性函数 φ , μ , σ , d φ,μ,σ,d φ,μ,σ,d
φ:欧拉函数
μ:莫比乌斯函数
d:约束个数函数 d = ∑ d ∣ n 1 d=\sum_{d|n}1 d=dn1
σ:约束和函数 σ ( n ) = ∑ d ∣ n d σ(n)=\sum_{d|n}d σ(n)=dnd

2、完全积性函数:任意两个数m、n,满足f(mn)=f(m)f(n)
常见完全积性函数 ϵ , I , i d ϵ,I,id ϵ,I,id
ϵ ϵ ϵ:元函数 ϵ ( n ) = [ n = 1 ] ϵ(n)=[n=1] ϵ(n)=[n=1]
I I I:恒等函数 I ( n ) = 1 I(n)=1 I(n)=1
i d id id:单位函数 i d ( n ) = n id(n)=n id(n)=n

狄利克雷卷积

定义:两个数论函数 f 和 g 的卷积为 ( f ∗ g ) ( n ) = ∑ d ∣ n f ( d ) g ( n d ) (f*g)(n)=\sum_{d|n}f(d)g(\frac nd) (fg)(n)=dnf(d)g(dn)
性质:和乘法差不多,满足交换律、结合律、分配律
1、交换律:交换的顺序,只是枚举的约数的顺序出现变化,每个约数的贡献不变
2、元函数: f ∗ ϵ = f f*\epsilon =f fϵ=f

欧拉函数

定义 φ ( n ) \varphi (n) φ(n)指小于等于n且与n互素的正整数的个数
公式 φ ( n ) = n ∏ i = 1 k ( 1 − 1 p i ) \varphi(n)=n \prod_{i=1}^{k} (1-\frac 1{p_i}) φ(n)=ni=1k(1pi1),k为不同的质因子的个数
性质
1、当n>2时, φ ( n ) \varphi (n) φ(n)为偶数
2、当n>1时,小于n的数中与n互质的数的总和是: φ ( n ) n 2 \frac {\varphi (n) n}{2} 2φ(n)n
3、n的所有因子的欧拉函数之和等于n: ∑ d ∣ n φ ( d ) = n \sum_{d|n}\varphi (d)=n dnφ(d)=n

欧拉函数的三种求法

1、直接求欧拉函数,也可以先筛出素数,然后用素数去化简

ll euler(ll n)
{
	ll ret=n,a=n;
	for(ll i=2;i*i<=a;++i)
	{
		if(a%i==0)
		{
			ret=ret/i*(i-1);
			while(a%i==0)
				a/=i;
		}
	}
	if(a>1)
		ret=ret/a*(a-1);
	return ret;
}

2、埃氏筛

int phi[maxn]; 
void euler(int n)
{
	for(int i=1;i<=n;++i)
		phi[i]=i;
	for(int i=2;i<=n;++i)
	{
		//相等表示i是质数。不相等,说明是合数,已经被更新过了 
		if(phi[i]==i)
		{
			//遍历i的倍数,i是质因子,据公式更新 
			for(int j=i;j<=n;j+=i)
				phi[j]=phi[j]/i*(i-1);	
		}
	}
}

3、欧拉筛求欧拉函数

const int N=1e5;
int visit[N+10],phi[N+10],prime[N+10],cnt;

void euler()
{
	phi[1]=1,cnt=0;		//1要特判 
	for (int i=2;i<=N;i++)
	{
		if(!visit[i])		//这代表i是质数
		{
			prime[++cnt]=i;
			phi[i]=i-1;
		}
		for (int j=1;j<=cnt&&prime[j]*i<=N;j++)	 
		{
			visit[i*prime[j]]=1;		//把这个合数标记掉 
			if (i%prime[j]==0)
			{
			//若prime[j]是i的质因子,据计算公式,i已经包括i*prime[j]的所有质因子
				phi[i*prime[j]]=phi[i]*prime[j]; 
				break;	//break用于这样能保证每个数只会被自己最小的因子筛掉一次 
			}
			else  //与质数不是倍数关系,就是互质 
				phi[i*prime[j]]=phi[i]*phi[prime[j]];	//积性函数 
		}
	}
}

不带注释

const int N=1e5;
int visit[N+10],phi[N+10],prime[N+10],cnt;

void euler()
{
	phi[1]=1,cnt=0;		
	for (int i=2;i<=N;i++)
	{
		if(!visit[i])		
		{
			prime[++cnt]=i;
			phi[i]=i-1;
		}
		for (int j=1;j<=cnt&&prime[j]*i<=N;j++)	 
		{
			visit[i*prime[j]]=1;		
			if (i%prime[j]==0)
			{
				phi[i*prime[j]]=phi[i]*prime[j]; 
				break;	
			}
			else phi[i*prime[j]]=phi[i]*phi[prime[j]];	
		}
	}
}

莫比乌斯函数

定义:每一个n可以分解为: n = p 1 k 1 p 2 k 2 … p s k s n=p_1^{k_1}p_2^{k_2}\dots p_s^{k_s} n=p1k1p2k2psks
μ ( n ) = { 1 ( n = 1 ) 0 ( ∃ k i ≥ 2 ) ( − 1 ) s ( ∀ k i = 1 ) \mu(n)=\begin{cases} 1 &(n=1) \\ 0 &(\exists k_i \ge2)\\ (-1)^s &(\forall k_i=1) \end{cases} μ(n)=10(1)s(n=1)(ki2)(ki=1)

性质
1、 ∑ d ∣ n u ( d ) = [ n = 1 ] \sum_{d|n}u(d)=[n=1] dnu(d)=[n=1]
2、 ∑ d ∣ n μ ( d ) n d = φ ( n ) \sum_{d|n} \mu(d) \frac nd=\varphi(n) dnμ(d)dn=φ(n)
证明:利用欧拉函数的性质: ∑ d ∣ n φ ( d ) = n \sum_{d|n}\varphi (d)=n dnφ(d)=n
写成卷积形式: φ ∗ I = i d \varphi *I=id φI=id
化简: φ ∗ I ∗ μ = i d ∗ μ \varphi *I*\mu=id*\mu φIμ=idμ ⟶ \longrightarrow φ ∗ ϵ = i d ∗ μ \varphi *\epsilon=id*\mu φϵ=idμ
φ ( n ) = ∑ d ∣ n u ( d ) i d ( n d ) = ∑ d ∣ n u ( d ) n d \varphi (n)=\sum_{d|n}u(d)id(\frac nd)=\sum_{d|n}u(d)\frac nd φ(n)=dnu(d)id(dn)=dnu(d)dn

线性筛莫比乌斯函数

const int N=5e4+5;
int prime[maxn],visit[maxn];
int mu[maxn],cnt;

void Mobius()
{
	memset(visit,0,sizeof(visit));
	memset(mu,0,sizeof(mu));
	cnt=0,mu[1]=1,visit[1]=1;
	for(int i=2;i<N;++i)
	{
		if(!visit[i])
			prime[++cnt]=i,mu[i]=-1;
		for(int j=1;j<=cnt&&i*prime[j]<N;++j)
		{
			visit[i*prime[j]]=1;
			if(i%prime[j]==0)
				break;
			mu[i*prime[j]]=-mu[i];
		}			
	}	
}

莫比乌斯反演

形式一:设f(n)是一个任意的函数, F ( n ) = ∑ d ∣ n f ( d ) F(n)=\sum_{d|n}f(d) F(n)=dnf(d)
反演可得: f ( n ) = ∑ d ∣ n μ ( d ) F ( n d ) f(n)=\sum_{d|n}\mu (d)F(\frac nd) f(n)=dnμ(d)F(dn)

证明 F ( n ) = ∑ d ∣ n f ( d ) = f ∗ I = F(n)=\sum_{d|n}f(d)=f*I= F(n)=dnf(d)=fI=
F ∗ μ = f ∗ I ∗ μ = f ∗ ( I ∗ u ) F*\mu =f*I*\mu=f*(I*u) Fμ=fIμ=f(Iu)
利用性质: ∑ d ∣ n u ( d ) = [ n = 1 ] \sum_{d|n}u(d)=[n=1] dnu(d)=[n=1]
因此: I ∗ μ = ϵ I*\mu =\epsilon Iμ=ϵ
f ∗ ( I ∗ μ ) = f ∗ ϵ = f = F ∗ μ = ∑ d ∣ n u ( d ) F ( n d ) f*(I*\mu)=f*\epsilon=f=F* \mu=\sum_{d|n}u(d)F(\frac nd) f(Iμ)=fϵ=f=Fμ=dnu(d)F(dn)

形式二:设f(n)是一个任意的函数, F ( n ) = ∑ n ∣ d f ( d ) F(n)=\sum_{n|d}f(d) F(n)=ndf(d)
反演可得: f ( n ) = ∑ n ∣ d μ ( d n ) F ( d ) f(n)=\sum_{n|d}\mu (\frac dn)F(d) f(n)=ndμ(nd)F(d)

杜教筛

用途:计算积性函数的前缀和,时间复杂度为 O ( n 2 3 ) O(n^{\frac 23}) O(n32)
1、需要计算: ∑ i = 1 n f ( i ) \sum_{i=1}^nf(i) i=1nf(i)
2、构造两个积性函数h和g满足: h = f ∗ g h=f*g h=fg
3、推导:先计算 ∑ i = 1 n h ( i ) \sum_{i=1}^n h(i) i=1nh(i),设 S ( n ) S(n) S(n) f ( i ) f(i) f(i)前缀和

∑ i = 1 n h ( i ) = ∑ i = 1 n ∑ d ∣ i g ( d ) f ( i d ) \sum_{i=1}^n h(i)=\sum_{i=1}^n\sum_{d|i}g(d)f(\frac id) i=1nh(i)=i=1ndig(d)f(di)

= ∑ d = 1 n g ( d ) ∑ i = 1 n d f ( i ) =\sum_{d=1}^n g(d)\sum_{i=1}^{\frac nd}f(i) =d=1ng(d)i=1dnf(i)

= ∑ d = 1 n g ( d ) S ( n d ) =\sum_{d=1}^n g(d) S(\frac nd) =d=1ng(d)S(dn)

= g ( 1 ) S ( n ) + ∑ d = 2 n g ( d ) S ( n d ) =g(1)S(n)+\sum_{d=2}^n g(d) S(\frac nd) =g(1)S(n)+d=2ng(d)S(dn)

因此可得:
g ( 1 ) S ( n ) = ∑ i = 1 n h ( i ) − ∑ d = 2 n g ( d ) S ( n d ) g(1)S(n)=\sum_{i=1}^n h(i) - \sum_{d=2}^n g(d) S(\frac nd) g(1)S(n)=i=1nh(i)d=2ng(d)S(dn)

例一:求 S ( n ) = ∑ i = 1 n μ ( i ) S(n)=\sum_{i=1}^n\mu(i) S(n)=i=1nμ(i)
我们很容易想到: μ ∗ I = ϵ \mu*I=\epsilon μI=ϵ,对 ϵ \epsilon ϵ求求前缀和就是1
g ( 1 ) S ( n ) = ∑ i = 1 n h ( i ) − ∑ d = 2 n g ( d ) S ( ⌊ n d ⌋ ) g(1)S(n)=\sum_{i=1}^n h(i) - \sum_{d=2}^n g(d) S(\lfloor \frac nd \rfloor) g(1)S(n)=i=1nh(i)d=2ng(d)S(dn)
该式可以化简为:
S ( n ) = 1 − ∑ d = 2 n S ( ⌊ n d ⌋ ) S(n)=1 - \sum_{d=2}^n S(\lfloor \frac nd \rfloor) S(n)=1d=2nS(dn)

例二:求 S ( n ) = ∑ i = 1 n φ ( i ) S(n)=\sum_{i=1}^n\varphi(i) S(n)=i=1nφ(i)
我们知道: φ ∗ I = i d \varphi *I=id φI=id
因此同样可以化简为:
S ( n ) = ∑ i = 1 n i − ∑ d = 2 n S ( ⌊ n d ⌋ ) S(n)=\sum_{i=1}^n i- \sum_{d=2}^n S(\lfloor \frac nd \rfloor) S(n)=i=1nid=2nS(dn)

例三:求 S ( n ) = ∑ i = 1 n i × φ ( i ) S(n)=\sum_{i=1}^{n}i \times \varphi(i) S(n)=i=1ni×φ(i)
(1)我们观察: f ( i ) = i × φ ( i ) f(i)=i \times \varphi(i) f(i)=i×φ(i)
(2)然后考虑: f ∗ g f*g fg的卷积形式: h = f ∗ g = ∑ d ∣ n d × φ ( d )   g ( n d ) h=f*g=\sum_{d|n}d\times \varphi(d)\ g(\frac nd) h=fg=dnd×φ(d) g(dn)
(3)很明显,我们想要消去这个d,因此取g=id
化简: h = ∑ d ∣ n d × φ ( d )   n d = ∑ d ∣ n n × φ ( d ) = n 2 h=\sum_{d|n}d\times \varphi(d)\ \frac nd=\sum_{d|n}n\times \varphi(d)=n^2 h=dnd×φ(d) dn=dnn×φ(d)=n2
(4)因此可以得到:
S ( n ) = ∑ i = 1 n i 2 − ∑ d = 2 n S ( ⌊ n d ⌋ ) S(n)=\sum_{i=1}^n i^2- \sum_{d=2}^n S(\lfloor \frac nd \rfloor) S(n)=i=1ni2d=2nS(dn)

P4213 【模板】杜教筛(Sum)

题意:求欧拉函数和莫比乌斯函数的前缀和
分析:模板题。需要使用:快读、unordered_map记忆化、整除分块不能全用long long

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <queue>
#include <vector>
#include <set>
#include <map>
#include <unordered_map>
#include <cstring>
#include <string>
#include <cmath>
#define rep(i,a,b) for (int i=a; i<=b; ++i)
#define per(i,b,a) for (int i=b; i>=a; --i)
#define mes(a,b)  memset(a,b,sizeof(a))
#define mp make_pair
#define ll long long
#define pb push_back
#define pii pair<int,int>
#define pll pair<ll,ll>
#define ls (rt<<1)
#define rs ((rt<<1)|1)
#define isZero(d)  (abs(d) < 1e-8)
using namespace std;
const int maxn=6e6+10,INF=0x3f3f3f3f;
const int mod=1e9+7;

inline int read() 
{
    int X=0,w=1; 
	char c=getchar();
    while (c<'0'||c>'9') 
	{ 
		if (c=='-') w=-1; 
		c=getchar(); 
	}
    while (c>='0'&&c<='9') 
		X=X*10+c-'0',c=getchar();
    return X*w;
}

int T,n;

const int N=6e6;
ll phi[maxn];
int visit[maxn],prime[maxn],mu[maxn],cnt;

inline void init()
{
	mu[1]=1,phi[1]=1,cnt=0;
	for(int i=2;i<=N;++i)
	{
		if(!visit[i])
			prime[++cnt]=i,phi[i]=i-1,mu[i]=-1;
		for(int j=1;j<=cnt&&i*prime[j]<=N;++j)
		{
			visit[i*prime[j]]=1;
			if(i%prime[j]==0)
			{
				phi[i*prime[j]]=phi[i]*prime[j];
				break;
			}
			phi[i*prime[j]]=phi[i]*phi[prime[j]];
			mu[i*prime[j]]=-mu[i];
		}
	}
	for(int i=1;i<=N;++i)
		phi[i]+=phi[i-1],mu[i]+=mu[i-1];
	
}

unordered_map<int,ll> mphi;
unordered_map<int,int> mmu;

inline ll calphi(int n)
{
	if(n<=N)
		return phi[n];
	if(mphi[n])
		return mphi[n];
	int l=2,r;
	ll ans=1ll*(1+n)*n/2; 
	while(l<=n)
	{
		r=n/(n/l);
		ans-=1ll*(r-l+1)*calphi(n/l);
		l=r+1;
	}
	return mphi[n]=ans;
}

inline int calmu(int n)
{
	if(n<=N)
		return mu[n];
	if(mmu[n])
		return mmu[n];
	int l=2,r;
	ll ans=1;
	while(l<=n)
	{
		r=n/(n/l);
		ans-=1ll*(r-l+1)*calmu(n/l);
		l=r+1;
	} 
	return mmu[n]=ans;
}

int main()
{   
    init();
    T=read();
    while(T--)
    {
    	n=read();
    	printf("%lld %d\n",calphi(n),calmu(n));
    }
	return 0;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值