一、积性函数
1 定义
对于两个互质的正整数
n
,
m
n,m
n,m ,如果满足:
f
(
m
n
)
=
f
(
m
)
f
(
n
)
f(mn)=f(m)f(n)
f(mn)=f(m)f(n)
那么
f
(
x
)
f(x)
f(x) 这个函数就是一个积性函数。
如果对于任意两个正整数
n
,
m
n,m
n,m ,满足:
f
(
m
n
)
=
f
(
m
)
f
(
n
)
f(mn)=f(m)f(n)
f(mn)=f(m)f(n)
那么
f
(
x
)
f(x)
f(x) 就是一个完全积性函数。
2 积性函数举例
- 常数函数 f ( n ) = 1 f(n)=1 f(n)=1
- 单位函数
f
(
n
)
=
[
n
=
1
]
f(n)=[n=1]
f(n)=[n=1]
证明: f ( n ) ⋅ f ( m ) = { 0 e l s e 1 n = 1 , m = 1 = f ( n ) ( m ) f(n)\cdot f(m)=\{^{1\ n=1,m=1}_{0\ else}=f(n)(m) f(n)⋅f(m)={0 else1 n=1,m=1=f(n)(m) - 除数函数 σ k ( n ) = ∑ d ∣ n d k \sigma_k(n)=\sum_{d\mid n}d^k σk(n)=∑d∣ndk
- 欧拉函数 φ ( n ) = ∑ j = 1 n [ g c d ( i , n ) = 1 ] \varphi(n)=\sum^n_{j=1}[gcd(i,n)=1] φ(n)=∑j=1n[gcd(i,n)=1],又能写成 φ ( n ) = n ( 1 − 1 p 1 ) ( 1 − 1 p 2 ) … ( 1 − 1 p n ) \varphi(n)=n(1-\frac{1}{p_1})(1-\frac{1}{p_2})\ldots(1-\frac{1}{p_n}) φ(n)=n(1−p11)(1−p21)…(1−pn1),用来求比 n 小且与 n 互质的正整数个数。
- 莫比乌斯函数
μ
(
n
)
\mu(n)
μ(n)
性质:
∑ d ∣ n μ ( d ) = [ n = 1 ] = { 0 e l s e 1 n = 1 \sum_{d|n}\mu(d)=[n=1]=\lbrace^{1\ n=1}_{0\ else} d∣n∑μ(d)=[n=1]={0 else1 n=1
二、欧拉函数
以下有几个性质:(p均指质数)
- 若 n n n 是质数, φ ( n ) = n − 1 \varphi(n)=n-1 φ(n)=n−1 。
- 若 n = p n=p n=p, φ ( n ) = p k − k k − 1 \varphi(n)=p^k-k^{k-1} φ(n)=pk−kk−1
- 若 n n n 是奇数, φ ( 2 n ) = φ ( n ) \varphi(2n)=\varphi(n) φ(2n)=φ(n)
- ∑ d ∣ n φ = n \sum_{d|n}\varphi=n ∑d∣nφ=n
三、欧拉定理
若a与m互质,则:
a
ϕ
(
m
)
≡
1
(
m
o
d
m
)
a^{\phi(m)}\equiv 1(mod\ m)
aϕ(m)≡1(mod m)
这就是欧拉定理。欧拉定理、威尔逊定理、费马小定理、中国剩余定理并称为数论四大定理。
如果p是质数。那么:
a
p
−
1
≡
1
(
m
o
d
p
)
a^{p-1}\equiv 1(mod\ p)
ap−1≡1(mod p)
刚好我们发现从欧拉定理变成了费马小定理。也就是说,费马小定理是欧拉定理的一个特例。
而当
a
a
a 与
p
p
p 互质时:
a
b
≡
a
b
m
o
d
ϕ
(
p
)
(
m
o
d
p
)
a^b\equiv a^{b\ mod\ \phi(p)}(mod\ p)
ab≡ab mod ϕ(p)(mod p)
实际上,这是扩展欧拉定理的一部分,也叫欧拉降幂:
a
b
≡
{
a
b
b
<
ϕ
(
m
)
a
(
b
m
o
d
ϕ
(
m
)
)
+
ϕ
(
m
)
b
≥
ϕ
(
m
)
m
o
d
m
a^b\equiv\left\{ \begin{matrix} a^{b}~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~b<\phi(m)\\ a^{(b~mod~\phi(m))+\phi(m)} ~~~~~~~~~~~~b\ge \phi(m) \end{matrix}\right. mod ~~m
ab≡{ab b<ϕ(m)a(b mod ϕ(m))+ϕ(m) b≥ϕ(m)mod m
四、线性筛
1 简介
线性筛(又名欧拉筛),是一种用于找出一定范围内素数的算法。顾名思义,它能够在
O
(
n
)
O(n)
O(n) 的时间内完成任务。
线性筛的核心思想是每个合数只会被它的最小质因子筛去一次。我们从小到大枚举每个数,如果这个数是质数,就将它的倍数标记为非质数。同时,每个合数只会被它的最小质因子标记,避免了重复标记。
2 练习
2.1 题目描述
给定一个范围 [ 1 , n ] [1,n] [1,n] ,有 q q q 词询问,每次输出第 k k k 小的数。
2.2 代码
#include<bits/stdc++.h>
#define ll long long
using namespace std;
bool vis[100000002];
int prime[10000002],cnt;
int n,q;
void sieve(ll n){
vis[1]=1;
for(int i=2;i<=n;i++){
if(!vis[i]){
prime[++cnt]=i;
}
for(int j=1;j<=cnt&&i*prime[j]<=n;j++){
vis[i*prime[j]]=1;
if(i%prime[j]==0){
break;
}
}
}
}
int main(){
scanf("%d%d",&n,&q);
sieve(n);
while(q--){
int k;
scanf("%d",&k);
printf("%d\n",prime[k]);
}
return 0;
}
五、欧拉函数实践
1 求欧拉函数
1.1 题目描述
输入 n n n ,请输出 φ ( n ) \varphi(n) φ(n) 的值
1.2 思路
设 a n s ans ans 等于 n n n ,代表了小于 n n n 的所有正整数。当我们发现 n n n 可以被一个数 i i i 整除时,我们需要从 a n s ans ans 中减去那些也能被 i i i 整除的数。这些数的数量可以通过 a n s i \frac{ans}{i} ians 来计算。
1.3 代码
#include<bits/stdc++.h>
#define ll long long
#define bug printf("---OK---")
#define pa printf("A: ")
#define pr printf("\n")
#define pi acos(-1.0)
using namespace std;
ll n;
ll phi(ll n){
ll ans=n;
for(int i=2;i<=sqrt(n);i++){
if(n%i==0){
while(n%i==0){//当n能被i整除时,不断地除以i
n/=i;
}
ans-=ans/i;//从结果中减去ans/i
}
}
if(n>1){//如果n大于1,说明n是一个大于sqrt(n)的质数
ans-=ans/n;//从结果中减去ans/n
}
return ans;
}
int main(){
while(scanf("%lld",&n)&&n!=0){
printf("%lld\n",phi(n));
}
return 0;
}
2 Farey数列
1.1 题目描述
对于一个大于
1
1
1 的整数
n
n
n ,定义Farey序列
F
n
F_n
Fn 为一个分数集合
{
a
/
b
,
0
<
a
<
b
≤
n
\{{a/b},0<a<b\leq n
{a/b,0<a<b≤n 且
gcd
(
a
,
b
)
=
1
}
\gcd(a,b)=1\}
gcd(a,b)=1}
例如,前几项为
F
2
=
{
1
/
2
}
F_2=\{1/2\}
F2={1/2}
F
3
=
{
1
/
3
,
1
/
2
,
2
/
3
}
F_3=\{1/3,1/2,2/3\}
F3={1/3,1/2,2/3}
F
4
=
{
1
/
4
,
1
/
3
,
1
/
2
,
2
/
3
,
3
/
4
}
F_4=\{1/4,1/3,1/2,2/3,3/4\}
F4={1/4,1/3,1/2,2/3,3/4}
F
5
=
{
1
/
5
,
1
/
4
,
1
/
3
,
2
/
5
,
1
/
2
,
3
/
5
,
2
/
3
,
3
/
4
,
4
/
5
}
F_5=\{1/5,1/4,1/3,2/5,1/2,3/5,2/3,3/4,4/5\}
F5={1/5,1/4,1/3,2/5,1/2,3/5,2/3,3/4,4/5}
每次给定
n
n
n ,求
F
n
F_n
Fn 中分数的个数。
1.2 思路
分数没什么用,实际上是求欧拉函数前 n n n 项的和。
1.3 代码
#include<bits/stdc++.h>
#define ll long long
#define bug printf("---OK---")
#define pa printf("A: ")
#define pr printf("\n")
#define pi acos(-1.0)
using namespace std;
const ll N=1e6+2;
ll t,x;
ll phi[N],prime[N],tot;
void le(int n){//线性筛的同时求欧拉函数,降低时间复杂度
phi[1]=phi[0]=0;
for(int i=2;i<=n;i++){
if(!phi[i]){
phi[i]=i-1;
prime[++tot]=i;
}
for(int j=1;j<=tot&&i*prime[j]<=n;j++){
if(i%prime[j]==0){
phi[i*prime[j]]=phi[i]*prime[j];
break;
}
else{
phi[i*prime[j]]=phi[i]*(prime[j]-1);
}
}
}
}
int main(){
le(N);//预处理
for(int i=1;i<=N;i++){
phi[i]+=phi[i-1];//相加
}
while(scanf("%lld",&x)&&x!=0){
printf("%lld",phi[x]);pr;
}
return 0;
}
3 【模板】欧拉降幂
3.1 题目描述
求:
a
b
(
m
o
d
m
)
a^b(mod\ m)
ab(mod m)。
提示:
b
≤
1
0
200000000
b\le10^{200000000}
b≤10200000000
3.2 思路
由于b太大了,需要用欧拉降幂的公式。使用字符串处理即可。
3.3 代码
#include<bits/stdc++.h>
#define ll long long
#define bug printf("---OK---")
#define pa printf("A: ")
#define pr printf("\n")
#define pi acos(-1.0)
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;
ll a,m;
string s;
ll qpow(ll x,ll y){
ll ans=1;
while(y>0){
if(y&1==1){
ans=(ans*x)%m;
}
x=(x*x)%m;
y>>=1;
}
return ans;
}
ll oul(ll n){
ll ans=n;
for(ll i=2;i<=sqrt(n);i++){
if(n%i==0){
while(n%i==0){
n/=i;
}
ans-=ans/i;
}
}
if(n>1){
ans-=ans/n;
}
return ans;
}
ll downp(ll phi){
ll len=s.size();
ll b=0;
bool flag=0;
for(ll i=0;i<len;i++){
b=b*10+s[i]-'0';
if(b>=phi){
b%=phi;
flag=1;
}
}
if(flag==1){
b+=phi;
}
return b;
}
int main(){
cin>>a>>m>>s;
cout<<qpow(a,downp(oul(m)));
return 0;
}