目录
欧拉函数
n的分解质因数求欧拉函数
试除法求欧拉函数值
积性函数
筛法
朴素筛
埃氏筛
欧拉筛 (线性筛)
线性筛欧拉函数
快速幂
同余
欧拉定理
费马小定理
乘法逆元
欧拉函数
互质 :
∀
a
,
b
∈
N
,若
gcd
(
a
,
b
) = 1
,则
a
,
b
互质。
定义:
:
1 ∼
n
中与
n
互质的数的个数被称为欧拉函数,记作
φ
(
n
)
,即
n的分解质因数求欧拉函数
#include<iostream>
#include<algorithm>
using namespace std;
int eulerphi(int n) {
int p = n;
for (int i = 2; i * i < n; i++) {
if (n % i == 0) {
p = p / i * (i - 1);
while (n % i == 0) {
n /= i;
}
}
}
if (n > 1) {
p = p / n * (n - 1);
}
return p;
}
int main() {
int n;
while (cin >> n) {
cout << eulerphi(n) << endl;
}
return 0;
}
-
函数
eulerphi
用于计算给定整数n
的欧拉函数值。- 首先初始化变量
p
为n
,用于保存计算过程中的中间结果。 - 然后通过一个从
2
开始到小于n
的平方根的循环,依次检查每个数i
是否能整除n
。 - 如果能整除,就更新
p
的值为p / i * (i - 1)
,并通过一个内层循环将n
中包含的该质因数全部除去。 - 循环结束后,如果
n
仍然大于1
,说明n
本身就是一个质数,再次更新p
的值为p / n * (n - 1)
。 - 最后返回计算得到的欧拉函数值
p
。
- 首先初始化变量
-
在
main
函数中:- 定义了一个整数
n
。 - 通过一个
while
循环,不断读取用户输入的整数n
。 - 对于每个输入的
n
,调用eulerphi
函数计算其欧拉函数值,并将结果输出到控制台。
- 定义了一个整数
总的来说,这段代码的主要目的是根据输入的整数计算并输出其对应的欧拉函数值,核心在于通过分解质因数来逐步计算欧拉函数。
试除法求欧拉函数值
int phi(int x) {
int res = x;
for (int i = 2; i * i <= x; i ++) {
if (x % i == 0) {
res = res / i * (i - 1);
while (x % i == 0) {
x /= i;
}
}
}
if (x > 1) {
res = res / x * (x - 1);
}
return res;
}
积性函数
定义
∀
n
∈ Z +,有数论函数 f
(
n
)
满足
∀
a
,
b
,
gcd
(
a
,
b
) = 1
使得
f
(
a
×
b
) =
f
(
a
)
×
f
(
b
)
,则称
f (n) 为积性函数。
常见的积性函数
筛法
朴素筛
•
枚举
i
∈
[2
,
n
]
,标记
i
的倍数
2
×
i
,
3
×
i
,
· · ·
•
没被标记过的数就是质数。
vector<int> primes;
vector<bool> st;
void sieve(int n) {
st.resize(n + 1);
for (int i = 2; i <= n; i++) {
if (!st[i]) {
primes.push_back(i);
}
for (int j = 2 * i; j <= n; j += i) {
st[j] = true;
}
}
}
埃氏筛
•
对朴素筛进行优化,只需要考虑质数的倍数。
•
在枚举倍数时,因为
i
×
(2
∼
i
−
1)
已经被
2
∼
i
−
1
标记过,所以可以从 i *i 开始。
vector<int> primes;
vector<bool> st;
void sieve(int n) {
st.resize(n + 1);
for (int i = 2; i <= n; i++) {
if (!st[i]) {
primes.push_back(i);
for (int j = i * i; j <= n; j += i) {
st[j] = true;
}
}
}
}
欧拉筛 (线性筛)
•
考虑每个数的最小质因子。
•
维护一个质数数组,每次遍历
i
的时候从小到大枚举已有的每个质数
p
•
当
p
|
i
时,
p
一定是
i
的最小质因子,那么也一定是
i
×
p
的最小质因子。
•
当
p
∤
i
时,那么
p
一定比
i
的最小质因子小,所以
p
也一定是
i
×
p
的最小质因子。
vector<int> primes;
vector<bool> st;
void sieve(int n) {
st.resize(n + 1);
for (int i = 2; i <= n; i++) {
if (!st[i]) {
primes.push_back(i);
}
for (auto p : primes) {
if (i * p > n) {
break;
}
st[i * p] = true;
if (i % p == 0) {
break;
}
}
}
}
线性筛欧拉函数
•
若
i
为质数,
φ
(
i
) =
i
−
1
•
当
p
|
i
时,由于
p
已经是
i
的最小质因子,所以
φ
(
i
×
p
) =
φ
(
i
)
×
p
•
当
p
∤
i
时,此时
p
是
i
×
p
的一个新的最小质因子,所以
φ
(
i
×
p
) =
φ
(
i
)
×
(
p
−
1)
vector<int> primes, euler;
vector<bool> st;
void sieve(int n) {
st.resize(n + 1), euler.resize(n + 1), euler[1] = 1;
for (int i = 2; i <= n; i++) {
if (!st[i]) {
euler[i] = i - 1, primes.push_back(i);
}
for (auto p : primes) {
if (i * p > n) {
break;
}
st[i * p] = true;
if (i % p == 0) {
euler[i * p] = euler[i] * p;
break;
}
euler[i * p] = euler[i] * (p - 1);
}
}
}
快速幂
定义 :
快速幂可以 O
(
log
n
) 计算mod
p
考虑将指数用二进制来表示。最多有
+ 1
个二进制位。所以只需要用
O
(
log
n
)
次乘
法就可以算出答案。
int power(int a, int n, int p) {
int res = 1;
while (n) {
if (n & 1) {
res = 1LL * res * a % p;
}
a = 1LL * a * a % p;
n >>= 1;
}
return res;
}
同余
定义 :
若整数 a
,
b
除以正整数
m
所得的余数相等,则称
a
,
b
模
m
同余。记作
a
≡
b
(
mod
m
)
性质
性质
•
整除性:
m
|
(
a
−
b
)
,即
a
−
b
=
k
×
m
,
k
∈
Z
•
传递性:
a
≡
b
(
mod
m
)
,
b
≡
c
(
mod
m
)
⇒
a
≡
c
(
mod
m
)
•
基本运算:
a
≡
b
(
mod
m
)
,
c
≡
d
(
mod
m
)
⇒
a
±
c
≡
b
±
d
(
mod
m
)
a
≡
b
(mod m
)
,
c
≡
d
(mod
m) ⇒
a
×
c
≡
b
×
d (mod
m
)
a
≡
b
(mod
m
)
⇒
a
×
n
≡
b
×
n (mod m),
n
∈
Z
•
除法原理:若
k
×
a
≡
k
×
b
(
mod
m
)
,且
k
,
m
互质,则
a
≡
b (mod
m
)
欧拉定理
定义 :
若正整数 a
,
m
满足
gcd
(
a
,
m) = 1,
费马小定理
定义:
若质数 p
和正整数
a
满足
gcd
(
a
,
p
) = 1,则 ≡
1 (
mod
p
)
证明:由于
φ
(
p
) =
p
−
1
其中
p
为质数,所以根据欧拉定理得 ≡
1 (
mod
p
)
乘法逆元
定义:若 ax ≡
1 (
mod
p
)
,则称
x
是
a
模
p
意义下的乘法逆元。记作
费马小定理求逆元:
int inv(int a, int p) {
return power(a, p - 2, p);
}