数论——约数与欧拉函数

约数性质

根据试除法的结论,一个整数 N N N 的约数个数的上界为 2 N 2\sqrt N 2N

约数个数定理,其中 a i a_i ai 为质因子的次数(算术基本定理):
∏ i = 1 n ( a i + 1 ) \prod_{i=1}^n(a_i+1) i=1n(ai+1)

约数和定理(数学归纳法):
∏ i = 1 n ∑ j = 0 a i p i j \prod_{i=1}^n \sum_{j=0}^{a_i} p^j_i i=1nj=0aipij

i n t int int 范围内,一个正整数最多的约数个数为 1536 1536 1536

试除法求约数板子(注意易错点):

int getfactor(int x)
{
	int i;
	
	vector<int>ans;
	
	for(i=1;i<x/i;++i)
	{
		if(x%i==0)	ans.push_back(i),ans.push_back(x/i); 
	}
	
	if((ll)i*(ll)i==(ll)x)	ans.push_back(i);       //不能写 if(x%i==0)!!!!!
	
	sort(ans.begin(),ans.end());
	
	for(auto& x:ans)	printf("%d ",x);
	puts(""); 
}

欧拉函数(数论)的定义

对正整数n,欧拉函数是小于等于n的正整数中与n互质的数的数目

欧拉函数的性质(均正整数)

  1. 1 1 1 的欧拉函数是 1 1 1
    ϕ ( 1 ) = 1 \phi(1)=1 ϕ(1)=1

  2. 欧拉函数通项(证明:容斥原理)
    ϕ ( N ) = N ∏ p ∈ p r i m e s p ∣ N ( 1 − 1 p ) ( N > 1 ) \phi(N)=N\prod_{p\in primes}^{p|N}(1-\frac{1}{p})\quad(N>1) ϕ(N)=NpprimespN(1p1)(N>1)

  3. 欧拉函数是非完全积性函数(易证),当 g c d ( m , n ) = 1 gcd(m,n)=1 gcd(m,n)=1 时:
    ϕ ( m n ) = ϕ ( m ) ϕ ( n ) \phi(mn)=\phi(m)\phi(n) ϕ(mn)=ϕ(m)ϕ(n)

  4. m ∈ N ∗ m\in N^* mN ( m m m 的约数的欧拉函数和等于 m m m):
    ∑ d ∣ m ϕ ( d ) = ∑ d ∣ m ϕ ( m d ) = m \sum_{d|m}\phi(d)=\sum_{d|m}\phi(\frac{m}{d})=m dmϕ(d)=dmϕ(dm)=m
    证明:
    a ∈ [ 1 , m ] , a ∈ N ∗ a\in[1,m],a\in N^* a[1,m],aN,则 a a a 可以取 m m m 种值

    d = g c d ( a , m ) d=gcd(a,m) d=gcd(a,m) ,则满足这个条件的 a a a ϕ ( m d ) \phi(\frac{m}{d}) ϕ(dm)

    所以 ∑ ϕ ( m d ) = m \sum\phi(\frac{m}{d})=m ϕ(dm)=m (划分角度考虑),证毕.

  5. N > 2 N>2 N>2 时, ϕ ( N ) ≡ 0 ( m o d   2 ) \phi(N)\equiv0 (mod\ 2) ϕ(N)0(mod 2) 证明:
    N > 2 N>2 N>2时: ϕ ( N ) = N ( p 1 − 1 p 1 ) ( p 2 − 1 p 2 ) . . . ( p k − 1 p k ) \phi(N)=N(\frac{p_1-1}{p_1})(\frac{p_2-1}{p_2})...(\frac{p_k-1}{p_k}) ϕ(N)=N(p1p11)(p2p21)...(pkpk1)
    N ∈ { 2 c } N\in\{2^c\} N{2c},很显然 ϕ ( N ) \phi(N) ϕ(N) 含有 2 2 2 因子
    N ∉ { 2 c } N\notin\{2^c\} N/{2c},则一定存在一个奇质因子 p o d d p_{odd} podd,使得 2 ∣ ( p o d d − 1 ) 2|(p_{odd}-1) 2(podd1),则 2 ∣ ϕ ( N ) 2|\phi(N) 2ϕ(N)
    证毕.

  6. n ≡ 1 ( m o d   2 ) n\equiv1(mod\ 2) n1(mod 2) 时(易证): ϕ ( 2 n ) = ϕ ( n ) \phi(2n)=\phi(n) ϕ(2n)=ϕ(n)

  7. 对于 x ∈ N ∗ , x > 1 x\in N^*,x>1 xNx>1: ∑ k = 1 x − 1 [ g c d ( k , x ) = 1 ] k = 1 2 x ϕ ( x ) \sum_{k=1}^{x-1}[gcd(k,x)=1]k=\frac{1}{2}x\phi(x) k=1x1[gcd(k,x)=1]k=21xϕ(x) 证明:
    由欧几里得算法思想可知: g c d ( x , k ) = g c d ( x , x − k ) gcd(x,k)=gcd(x,x-k) gcd(x,k)=gcd(x,xk)
    则对于满足 g c d ( k , x ) = 1 gcd(k,x)=1 gcd(k,x)=1 k k k x − k x-k xk ,一起贡献了 x x x 的值,而不满足则不贡献,由于重复计算,所以要整体除以二,证毕.

  8. m 1 , m 2 m_1,m_2 m1,m2 有相同的质因子种类 ( m = m 1 m 2 m=m_1m_2 m=m1m2)(易证): ϕ ( m ) = ϕ ( m 1 ) m 2 = ϕ ( m 2 ) m 1 \phi(m)=\phi(m_1)m_2=\phi(m_2)m_1 ϕ(m)=ϕ(m1)m2=ϕ(m2)m1

总结(引用自知乎)
在这里插入图片描述

例题

类型1:线性筛欧拉函数

题目传送门 Acwing 874
在这里插入图片描述
本题借助质数筛筛欧拉函数,时间复杂度 O ( N ) O(N) O(N)
在这里插入图片描述

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<vector>
#include<string>
#include<set>
#include<map>
#include<unordered_map>
#include<queue>

#define mez(x) memset(x,0,sizeof x)
#define mei(x) memset(x,0x3f,sizeof x)
#define lowbit(x) -x&x
#define inf 0x3f3f3f3f
#define INF 0x7fffffff
#define cu(x) cout<<x<<"--"<<endl
#define ex exit(0)
#define pn puts("")

using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
typedef vector<int> vc;

const int N=1e6+10;
int n,cnt;
ll ans;

bool st[N];
int primes[N];
int phi[N];

inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
	return x*f;
}

ll get_phi()
{
    int i,j;
    
    phi[1]=1;
    for(i=2;i<=n;++i)
    {
        if(!st[i])  primes[cnt++]=i,phi[i]=i-1;
        for(j=0;primes[j]<=n/i;++j)
        {
            st[i*primes[j]]=true;
            
            if(i%primes[j]==0)
            {
                phi[i*primes[j]]=phi[i]*primes[j];
                break;
            }
            else
                phi[i*primes[j]]=phi[i]*(primes[j]-1);
        }
    }
    for(i=1;i<=n;++i)   ans+=phi[i];
    return ans;
}

int main()
{
    scanf("%d",&n);
    
    printf("%lld",get_phi());
	
	return 0;
}

类型2:互质对的个数统计

题目传送门 Acwing 220
在这里插入图片描述
本题的本质是统计 1 − N ( N > 0 ) 1-N (N>0) 1N(N>0) 之间互质对的个数: − 1 + 2 ∑ k = 1 N ϕ ( k ) -1+2\sum_{k=1}^{N}\phi(k) 1+2k=1Nϕ(k)
由质数分布,本题应当从质数的角度去枚举个数,时间复杂度 O ( N + N l n ( N ) ) = O ( N ) O(N+\frac{N}{ln(N)})=O(N) O(N+ln(N)N)=O(N)
g c d ( x , y ) = p ( p ∈ p r i m e s ) gcd(x,y)=p\quad (p\in primes) gcd(x,y)=p(pprimes)
g c d ( x p , y p ) = 1 gcd(\frac{x}{p},\frac{y}{p})=1 gcd(px,py)=1
则质数 p p p 的贡献数量为 : − 1 + 2 ∑ k = 1 ⌊ N p ⌋ ϕ ( k ) -1+2\sum_{k=1}^{\lfloor \frac{N}{p} \rfloor}\phi(k) 1+2k=1pNϕ(k)
所以答案为:
∑ p ∈ p r i m e s p ∣ N ( − 1 + 2 ∑ k = 1 ⌊ N p ⌋ ϕ ( k ) ) \sum_{p\in primes}^{p|N}(-1+2\sum_{k=1}^{\lfloor \frac{N}{p} \rfloor}\phi(k)) pprimespN(1+2k=1pNϕ(k))
所以本题的核心步骤是筛质数和维护欧拉函数前缀和,注意LL

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<vector>
#include<string>
#include<set>
#include<map>
#include<unordered_map>
#include<queue>

#define mez(x) memset(x,0,sizeof x)
#define mei(x) memset(x,0x3f,sizeof x)
#define lowbit(x) -x&x
#define inf 0x3f3f3f3f
#define INF 0x7fffffff
#define cu(x) cout<<x<<"--"<<endl
#define ex exit(0)
#define pn puts("")

using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
typedef vector<int> vc;

inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
	return x*f;
}

const int N=1e7+10;
int n,cnt;

bool st[N];
int primes[N];
ll phi[N];

void get_primes()
{
    int i,j;
    
    phi[1]=1;
    for(i=2;i<=n;++i)
    {
        if(!st[i])  primes[cnt++]=i,phi[i]=i-1;
        for(j=0;primes[j]<=n/i;++j)
        {
            st[primes[j]*i]=true;
            if(i%primes[j]==0)
            {
                phi[i*primes[j]]=phi[i]*primes[j];
                break;
            }
            else
                phi[i*primes[j]]=phi[i]*(primes[j]-1);
        }
    }
    
    for(i=1;i<=n;++i)
        phi[i]+=phi[i-1];
}

int main()
{
    int i,j;
    ll ans=0;
    
    scanf("%d",&n);
    
    get_primes();
    
    for(i=0;i<cnt;++i)
        ans+=(-1LL+2LL*phi[n/primes[i]]);
    
    printf("%lld",ans);
	
	return 0;
}

类型3:欧拉函数积性的运用

题目传送门 POJ2480
在这里插入图片描述
本题的本质是求: f ( N ) = ∑ i = 1 N g c d ( i , N ) f(N)=\sum_{i=1}^{N}gcd(i,N) f(N)=i=1Ngcd(i,N)
首先,肯定不能暴力求。按照上一个题的思想,从 N N N 的约数入手,对于 M , M ∣ N M,M|N M,MN,设:
g c d ( i ′ , N ) = M ( i ′ ≥ M ) gcd(i^{\prime},N)=M\quad(i^{\prime}\ge M) gcd(i,N)=M(iM)
那么,满足条件的 i ′ i^{\prime} i 的个数怎么求? 先对 i ′ i^{\prime} i N N N 分解:
i ′ = M ∗ j , N = M ∗ j ′ i^{\prime}=M*j,\quad N=M*j^{\prime} i=Mj,N=Mj
很明显,满足条件的 i ′ i^{\prime} i 的个数为 ϕ ( N M ) \phi(\frac{N}{M}) ϕ(MN),所以约数 M M M 对答案的贡献为 M ϕ ( N M ) M\phi(\frac{N}{M}) Mϕ(MN)
本题的结果呼之欲出:
f ( N ) = ∑ d ∣ N d ϕ ( N d ) f(N)=\sum_{d|N}d\phi(\frac{N}{d}) f(N)=dNdϕ(dN)
若根据上式直接求解,时间复杂度 O ( N ) O(\sqrt N) O(N ),我们可以利用欧拉函数的积性优化时间,下面我们来探讨 f ( N ) f(N) f(N) 的积性:
不妨设: f ( n ) = ∑ d 1 ∣ n d 1 ϕ ( n d 1 ) , f ( m ) = ∑ d 2 ∣ m d 2 ϕ ( m d 2 ) f(n)=\sum_{d_1|n}d_1\phi(\frac{n}{d_1}),\quad f(m)=\sum_{d_2|m}d_2\phi(\frac{m}{d_2}) f(n)=d1nd1ϕ(d1n),f(m)=d2md2ϕ(d2m)
乘法分配律和欧拉函数的积性易得: f ( n ) f ( m ) = ∑ d ∣ n m d ϕ ( n m d ) f(n)f(m)=\sum_{d|nm}d\phi(\frac{nm}{d}) f(n)f(m)=dnmdϕ(dnm)
所以: f ( N ) f(N) f(N) 也为积性函数
由算数基本定理,可以对 N N N 进行分解:
N = p 1 c 1   p 2 c 2   . . . . p k c k ( p i ∈ p r i m e s ) N=p_1^{c_1}\ p_2^{c_2}\ .... p_k^{c_k}\quad (p_i\in primes) N=p1c1 p2c2 ....pkck(piprimes)
f ( N ) = f ( p 1 c 1   p 2 c 2   . . . . p k c k ) f(N)=f(p_1^{c_1}\ p_2^{c_2}\ .... p_k^{c_k}) f(N)=f(p1c1 p2c2 ....pkck)
以其中一个为例子
f ( p c ) = ∑ i = 0 c p i ϕ ( p c p i ) = p c ϕ ( 1 ) + ∑ i = 0 c − 1 p i ϕ ( p c p i ) f(p^c)=\sum_{i=0}^cp^i\phi(\frac{p^c}{p^i})=p^c\phi(1)+\sum_{i=0}^{c-1}p^i\phi(\frac{p^c}{p^i}) f(pc)=i=0cpiϕ(pipc)=pcϕ(1)+i=0c1piϕ(pipc)
∑ i = 0 c − 1 p i ϕ ( p c p i ) = ∑ i = 0 c − 1 p i ( p c − i ) ( 1 − 1 p ) = ∑ i = 0 c − 1 p c − p c − 1 = c ( p c − p c − 1 ) \sum_{i=0}^{c-1}p^i\phi(\frac{p^c}{p^i})=\sum_{i=0}^{c-1}p^i(p^{c-i})(1-\frac{1}{p})=\sum_{i=0}^{c-1}p^c-p^{c-1}=c(p^c-p^{c-1}) i=0c1piϕ(pipc)=i=0c1pi(pci)(1p1)=i=0c1pcpc1=c(pcpc1)
f ( p c ) = ( c + 1 ) p c − c p c − 1 f(p^c)=(c+1)p^c-cp^{c-1} f(pc)=(c+1)pccpc1
最终可得:
f ( N ) = ∏ p ∈ p r i m e s p ∣ N ( ( c + 1 ) p c − c p c − 1 ) f(N)=\prod_{p\in primes}^{p|N}((c+1)p^c-cp^{c-1}) f(N)=pprimespN((c+1)pccpc1)
所以,欧拉函数在本题中只是个过渡作用,本质是分解质因数+快速幂

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<vector>
#include<string>
#include<set>
#include<map>
//#include<unordered_map>
#include<queue>

#define mez(x) memset(x,0,sizeof x)
#define mei(x) memset(x,0x3f,sizeof x)
#define lowbit(x) -x&x
#define inf 0x3f3f3f3f
#define INF 0x7fffffff
#define cu(x) cout<<x<<"--"<<endl
#define ex exit(0)
#define pn puts("")

using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
typedef vector<int> vc;

inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
	return x*f;
}

ll qmi(ll a,ll b)
{
	ll ans=1;
	
	while(b)
	{
		if(b&1)	ans*=a;
		a*=a;
		b>>=1;
	}
	
	return ans;
}

ll get_ans(ll target)
{
	ll i,nums,ans=1,temp;
	
	for(i=2;i*i<=target;++i)
	{
		if(target%i==0)
		{
			nums=0;
			while(target%i==0)	target/=i,++nums;
			temp=qmi(i,nums);
			ans*=(nums+1)*temp-nums*(temp/i);
		}
	}
	
	if(target>1)	ans*=2*target-1;
	
	return ans;
}

int main()
{
	ll n;
	
	while(~scanf("%lld",&n))
		printf("%lld\n",get_ans(n));	
	
	return 0;
}
附加:

在这里插入图片描述

求解 g ( N ) = ∑ i = 1 N l c m ( i , N ) g(N)=\sum_{i=1}^{N}lcm(i,N) g(N)=i=1Nlcm(i,N)
本题和上题类似,就是公式推导过程中由些许不同:
类似地,我们还是从约数的角度出发,设 M M M N N N 的约数,设 g c d ( i ′ , N ) = M gcd(i^{\prime},N)=M gcd(i,N)=M
i ′ = M ∗ j , N = M ∗ j ′ i^{\prime}=M*j,\quad N=M*j^{\prime} i=Mj,N=Mj
可得约数 M M M 的贡献值为:
∑ i ′ N M = N ∑ j = N ∗ ( 1 2 j ′ ϕ ( j ′ ) ) ( M ≠ N ) \sum\frac{i^{\prime}N}{M}=N\sum j=N*(\frac{1}{2}j^{\prime}\phi(j^{\prime}))\quad (M\neq N) MiN=Nj=N(21jϕ(j))(M=N)
(注意:为什么 M ≠ N M\neq N M=N ? 因为求和公式的条件是 j ′ > 1 j^{\prime}>1 j>1,所以最后要把 M = N M=N M=N的贡献单独加上)
所以可得:
g ( N ) = N + N 2 ∑ d ∣ N , d ≠ N N d ϕ ( N d ) g(N)=N+\frac{N}{2}\sum_{d|N,d\neq N}\frac{N}{d}\phi(\frac{N}{d}) g(N)=N+2NdN,d=NdNϕ(dN)
转化一下:
g ( N ) = N + N 2 ∑ d ∣ N , d ≠ 1 d ϕ ( d ) g(N)=N+\frac{N}{2}\sum_{d|N,d\neq 1}d\phi(d) g(N)=N+2NdN,d=1dϕ(d)
若 直接枚举约数的话(时间复杂度 O ( N ) O(\sqrt N) O(N )
namo:
在这里插入图片描述
由于int范围内的最多约数个数是1536,所以可以分解质因数后约束搜索一下,虽然理论复杂度差不多,但明显效率快好几倍…
在这里插入图片描述

#include<cstdio>
#include<cstring>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<vector>
#include<string>
#include<set>
#include<map>
#include<unordered_map>
#include<queue>

#define mez(x) memset(x,0,sizeof x)
#define mei(x) memset(x,0x3f,sizeof x)
#define lowbit(x) -x&x
#define inf 0x3f3f3f3f
#define INF 0x7fffffff
#define cu(x) cout<<x<<"--"<<endl
#define ex exit(0)
#define pn puts("")

using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
typedef vector<int> vc;

inline int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}
	while (ch>='0'&&ch<='9'){x=x*10+ch-48;ch=getchar();}
	return x*f;
}

const int N=1e6,M=1600;
int t,cnt,idx,nums; 

ll primes[N+3],phi[N+3],p[M],q[M],fa[M];
bool st[N+3];

void get_primes()
{
	ll i,j;
	
	phi[1]=1;
	for(i=2;i<=N;++i)
	{
		if(!st[i])	primes[cnt++]=i,phi[i]=i-1;
		for(j=0;primes[j]<=N/i;++j)
		{
			st[primes[j]*i]=true;
			if(i%primes[j]==0)
			{
				phi[i*primes[j]]=phi[i]*primes[j];
				break;
			}
			else
				phi[i*primes[j]]=phi[i]*(primes[j]-1);
		}
	}
}

inline void get_factor(int t)
{
	ll i,j;
	
	for(i=2;i<=t/i;++i)
	{
		if(t%i==0)
		{
			j=0;
			while(t%i==0) t/=i,++j;
			p[idx]=i;
			q[idx++]=j;
		}
	}
	if(t>1)	p[idx]=t,q[idx++]=1;
}

void dfs(int i,int now)
{
	if(i==idx)
	{
		fa[nums++]=now;
		return;
	}
	
	int k;
	
	for(k=0;k<=q[i];++k,now*=p[i])
		dfs(i+1,now);
}

ll get_ans(ll t)
{
	ll temp=0;
	nums=idx=0;
	
	get_factor(t);
	dfs(0,1);
	
	for(int i=1;i<nums;++i)
		temp+=fa[i]*phi[fa[i]];
	temp=temp*t/2;
	temp+=t;
	
	return temp;
}

int main()
{
	int temp;
	
	get_primes();
	
	t=read();
	while(t--)
	{
		temp=read();
		if(temp<=0)	printf("%d\n",0);
		else	printf("%lld\n",get_ans((ll)temp));
	}
	
	return 0;
}

未完待续

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值