约数性质
根据试除法的结论,一个整数 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=1∏n(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=1∏nj=0∑aipij
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 \phi(1)=1 ϕ(1)=1 -
欧拉函数通项(证明:容斥原理)
ϕ ( 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)=Np∈primes∏p∣N(1−p1)(N>1) -
欧拉函数是非完全积性函数(易证),当 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) -
若 m ∈ N ∗ m\in N^* m∈N∗ ( 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 d∣m∑ϕ(d)=d∣m∑ϕ(dm)=m
证明:
设 a ∈ [ 1 , m ] , a ∈ N ∗ a\in[1,m],a\in N^* a∈[1,m],a∈N∗,则 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 (划分角度考虑),证毕.
-
当 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(p1p1−1)(p2p2−1)...(pkpk−1)
当 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∣(podd−1),则 2 ∣ ϕ ( N ) 2|\phi(N) 2∣ϕ(N)
证毕. -
当 n ≡ 1 ( m o d 2 ) n\equiv1(mod\ 2) n≡1(mod 2) 时(易证): ϕ ( 2 n ) = ϕ ( n ) \phi(2n)=\phi(n) ϕ(2n)=ϕ(n)
-
对于 x ∈ N ∗ , x > 1 x\in N^*,x>1 x∈N∗,x>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=1∑x−1[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,x−k)
则对于满足 g c d ( k , x ) = 1 gcd(k,x)=1 gcd(k,x)=1 的 k k k 与 x − k x-k x−k ,一起贡献了 x x x 的值,而不满足则不贡献,由于重复计算,所以要整体除以二,证毕. -
若 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)
1−N(N>0) 之间互质对的个数:
−
1
+
2
∑
k
=
1
N
ϕ
(
k
)
-1+2\sum_{k=1}^{N}\phi(k)
−1+2k=1∑Nϕ(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(p∈primes)
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=1∑⌊pN⌋ϕ(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))
p∈primes∑p∣N(−1+2k=1∑⌊pN⌋ϕ(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=1∑Ngcd(i,N)
首先,肯定不能暴力求。按照上一个题的思想,从
N
N
N 的约数入手,对于
M
,
M
∣
N
M,M|N
M,M∣N,设:
g
c
d
(
i
′
,
N
)
=
M
(
i
′
≥
M
)
gcd(i^{\prime},N)=M\quad(i^{\prime}\ge M)
gcd(i′,N)=M(i′≥M)
那么,满足条件的
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′=M∗j,N=M∗j′
很明显,满足条件的
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)=d∣N∑dϕ(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)=d1∣n∑d1ϕ(d1n),f(m)=d2∣m∑d2ϕ(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)=d∣nm∑dϕ(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(pi∈primes)
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=0∑cpiϕ(pipc)=pcϕ(1)+i=0∑c−1piϕ(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=0∑c−1piϕ(pipc)=i=0∑c−1pi(pc−i)(1−p1)=i=0∑c−1pc−pc−1=c(pc−pc−1)
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)pc−cpc−1
最终可得:
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)=p∈primes∏p∣N((c+1)pc−cpc−1)
所以,欧拉函数在本题中只是个过渡作用,本质是分解质因数+快速幂
#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=1∑Nlcm(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′=M∗j,N=M∗j′
可得约数
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)
∑Mi′N=N∑j=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+2Nd∣N,d=N∑dNϕ(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+2Nd∣N,d=1∑dϕ(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;
}
未完待续