算法 {质数,互质,质因数分解}
質數
性质
#质数个数#
[1,N]
里面的质数个数 大约是N / ln(N)
;
@DELI;
常见质数:
[2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53,59,61,67,71,73,79,83,89,97]
;
@DELI;
特殊的质数:
2147483647, 9223372036854775807, {1|2}e9+7, {1|2|3}e18+7
;
@DELI;
int
范围内 相邻两个质数的差值 都是< 300
的;
@DELI;
int
范围内, 拥有最多的不同质因子个数的是:
{
2
,
3
,
5
,
7
,
11
,
13
,
17
,
19
,
23
}
\{2, 3,5,7,11,13,17,19,23 \}
{2,3,5,7,11,13,17,19,23}她的乘积是 223092870
;
int64
范围内 是
{
2
,
3
,
5
,
7
,
11
,
13
,
17
,
19
,
23
,
29
,
31
,
37
,
41
,
43
,
47
}
\{2, 3,5,7,11,13,17,19,23,29,31,37,41,43,47\}
{2,3,5,7,11,13,17,19,23,29,31,37,41,43,47};
代码
線性篩質數 ( O ( N ) O(N) O(N))
namespace ___LinearSieve_Primes{ // 線性篩質數 ($O(N)$)
constexpr int __Range = ?; // 處理的數據範圍是`[2...Range)`;
bool Is_prime[__Range]; // `Is_prime[a]`表示`a`是否為質數;
vector<int> Primes; // [2,3,5,7,...] 表示`[1,...,Range]`裡所有的質數;
int PrimeFactor[__Range]; // `a=PrimeFactor[b]`: `a`为`b`的最大的质因子;
void Initialize(){ // 处理的數據范围為`[1,...,range]`;
Primes.reserve( __Range); Primes.clear();
memset( Is_prime, true, sizeof( Is_prime)); Is_prime[1]=false;
for( int num = 2; num < __Range; ++num){
if( Is_prime[ num]){
Primes.push_back( num);
PrimeFactor[ num] = num;
}
for( int ind = 0;; ++ind){
int tar = Primes[ ind] * num; if( tar >= __Range){ break;}
Is_prime[ tar] = false;
PrimeFactor[ tar] = PrimeFactor[num]; // 如果是`=Primes[ind]` 則對應為最小質因子;
//>< `num`的最小的質因子 一定是`>= Primes[ind]`;
if( num % Primes[ ind] == 0){ // 比如`num`的質因子為`{5,11}`, 那麼此時`Primes[ind] == 5`;
break;
}
//>< 比如`num`的質因子為`{5,11}`, 那麼此時`Primes[ind] == {2/3}`;
}
}
}
} // namespace ___LinearSieve_Primes
@TODO: ___LinearSieve_Primes::Initialize();
判断一個數是否为质数 O ( N ) O( \sqrt{N}) O(N)
template< typename _Type> bool ___IsPrime( _Type _a){
if( _a < 2){ return false;}
for( _Type i = 2; i <= _a / i; ++i){ if( _a % i == 0){ return false;}}
return true;
} // ___IsPrime
错误
质数的无穷性
错误证明: 因为质数的量级可以是无穷的 即
p
a
p^a
pa 其中
a
a
a是无穷的;
.
这是错误的, 不要凭感觉说质数是无穷的, 因为没准所有的数 的质因数分解 都是某个质数集合里面的数 比如所有数的质因子都是{2,3,5,...,Ma}
这个集合里面的;
正确证明: 假如质数是有限的a,b,c,...,z
, 则a*b*...*z
这个数 同时是a/b/.../z
的倍数, 因此(a*b*...*z) + 1
这个数 一定不是a/b/.../z
的倍数, 因为他是质数;
筆記
@DELIMITER
Property-1
[
1
,
n
]
[1,n]
[1,n]内的质数个数
The Primes-Count in [ 1 , n ] [1,n] [1,n] is approximately n ln n \displaystyle{ \frac{n}{\ln{n} }} lnnn;
@Delimiter
Property-2
0
0
0与任何正数互质
(
0
,
x
)
(0, x)
(0,x) is Co-Prime
⟺
\iff
⟺
x
∈
N
+
x \in N^+
x∈N+
.
Notice,
(
0
,
0
)
(0,0)
(0,0) is not Coprime;
Property-3
1
1
1与任何自然数互质
(
1
,
x
)
(1, x)
(1,x) is Co-Prime
⟺
\iff
⟺
x
∈
N
x \in N
x∈N
.
As a lemma, the Euler-Function of
1
1
1 equals to
1
1
1;
@Delimiter
Property-4
(
a
,
b
)
(a,b)
(a,b)互质的等价代换
(
a
,
b
)
(a,b)
(a,b) is Co-Prime
→
\to
→
G
C
D
(
a
,
b
)
=
1
GCD(a,b)=1
GCD(a,b)=1
.
As discussed above,
(
1
,
1
)
(
1
,
0
)
(1,1) (1,0)
(1,1)(1,0) is Coprime while
(
0
,
0
)
(0,0)
(0,0) is not, the
a
,
b
a,b
a,b in
G
C
D
(
a
,
b
)
GCD(a,b)
GCD(a,b) must be
N
N
N and not both
0
0
0;
@Delimiter
Property-5
两数乘积的质因子不变
Let
S
1
S1
S1 be the Prime-Factors set of the number
a
a
a,
S
2
S2
S2 be the set of
b
b
b; then the Prime-Factors set of
a
∗
b
a * b
a∗b must be
S
1
∨
S
2
S1 \lor S2
S1∨S2;
.
In other words, any Prime-Factor of
a
∗
b
a * b
a∗b must be also a Prime-Factor of at least one of
a
,
b
a, b
a,b;
.
As a corollary, every Prime-Factor of
n
!
n!
n! must
≤
n
\leq n
≤n, although the number
n
!
n!
n! maybe very large;
@Delimiter
Property-6
合数的最小质因子
If
x
x
x is not a Prime-Number, then
m
i
n
(
p
i
)
≤
x
min(p_i) \leq \sqrt{ x}
min(pi)≤x (in other words, there must exist a Prime-Factors
p
p
p of
x
x
x such that
p
∣
x
∧
p
∈
[
1
,
x
]
p | x \ \ \land \ \ p \in [1, \sqrt{x}]
p∣x ∧ p∈[1,x])
.
Example: AcWing-198. 反素数
@Delimiter
Property-7
一个数的质因子个数
+
Let
S
S
S be the multiset of all Prime-Factors of an arbitrary-integer
a
a
a, then the maximal
S
.
s
i
z
e
(
)
S.size()
S.size() is
log
2
(
a
)
\log_2(a)
log2(a) (i.e.,
S
=
{
2
,
2
,
.
.
.
,
2
}
S=\{2,2,...,2\}
S={2,2,...,2})
+
Let
S
S
S be the set of all Prime-Factors of an arbitrary-integer
a
a
a, then
.
If the type of
a
a
a is int
, the maximal
S
.
s
i
z
e
(
)
S.size()
S.size() is
9
9
9 (i.e.,
S
=
{
2
,
3
,
5
,
7
,
11
,
13
,
17
,
19
,
23
}
S=\{2, 3,5,7,11,13,17,19,23 \}
S={2,3,5,7,11,13,17,19,23} whose product is 223092870
; if you proceed multiple the next-prime 29
then it would be 6469693230
which is Out-Of-UINT32_MAX
)
.
If the type of
a
a
a is long long
, the maximal
S
.
s
i
z
e
(
)
S.size()
S.size() is
15
15
15 (i.e.,
S
=
{
2
,
3
,
5
,
7
,
11
,
13
,
17
,
19
,
23
,
29
,
31
,
37
,
41
,
43
,
47
}
S=\{2, 3,5,7,11,13,17,19,23,29,31,37,41,43,47\}
S={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47} whose product is 614889782588491410
; ; if you proceed multiple the next-prime 53
then it would be Out-Of-UINT64_MAX
)
互質
定義
#两个数的互质#
對於两个整數a,b
且他俩有GCD(即不同时为0), 如果GCD(a,b) == 1
, 則他倆互質;
.
等价定义: a的約數集合與b的約數集合的交集 为{1}
;
@DELI;
#若干个数的互质#
對於若干整數Ai
且他们有GCD(即不同时为0), 如果GCD( 所有Ai ) == 1
, 则他们互质;
性質
因為GCD(1,1) = 1
, 所以1,1
互質;
因為GCD(0,1) = 1
, 所以0,1
互質;
算法
求 A × B A\times B A×B裡 互質的數對個數
@LINK: https://editor.csdn.net/md/?not_checkout=1&articleId=130248080
;
求 N × N N\times N N×N裡互質的數對的個數
@LINK: (https://editor.csdn.net/md/?articleId=126848932)-(@LOC_0)
;
質因數分解
定義
對於正整數a, 他可以寫成p1^k1 * p2^k2 * ...
的性質 其中pi
為質數 k1>=1
, 即可以用{(p1,k2), (p2,k2), ...}
來表示任何正整數;
性質
<= 1e9
的数, 其质因子最多有9
; (即前10个质数相乘的结果 是大于1e9
的);
<= 1e16
的数, 其质因子最多有13
; (即前14个质数相乘的结果 是大于1e16
的);
<= 9e18
的数, 其质因子最多有15
; (即前16个质数相乘的结果 是大于9e18
的);
@DELI;
#1的質因數分解為空#
比如12
的質因數分解為{(2,2), (3,1)}
; 而1的質因數分解為{}
, 不要把它形成是{(2,0)}
這樣的話 一個數的質因數分解就不唯一了;
因此, #任意數的質因數分解 都是唯一確定的#;
@DELI;
一個數a的質因數分解p1^k1 * p2^k2 * ... * pn^kn
;
.
k1+k2+...
的最大值為
log
2
(
a
)
\log_2(a)
log2(a), 即二次冪 2*2*...*2
這個數;
.
n
的最大值 (即不同質因子的個數), 對於int
是9
對應2 * 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23
這個數; 對於int64
他是15
對應2 * 3,5,7,11,13,17,19,23,29,31,37,41,43,47
這個數;
算法
求一個數的质因数分解
O ( a ) O(\sqrt{a}) O(a)(暴力)
{ // 一個數的质因数分解 ($O(\sqrt{a})$)
auto ___a = ?;
map< decltype(___a), int> ___Factors; // `a`的質因數分解
for( int ___p = 2; ___p <= ___a / ___p; ++___p){
if( ___a % ___p == 0){
int ___k = 0;
while( ___a % ___p == 0){
++ ___k;
___a /= ___p;
}
___Factors[ ___p] = ___k;
}
}
if( ___a > 1){
___Factors[ ___a] = 1;
}
} // 一個數的质因数分解 ($O(\sqrt{a})$)
O ( 1 ) O(1) O(1)(预处理)
性質
求a的質因數分解, 需要提前對[1,a]
裡面的所有數 (線性篩質數可以)預處理出Ma(x)
表示x的最大/最小質因子;
代碼
{ // 一個數的质因数分解 ($O(1)$)
int ___a = ?;
for( int ___t = ___a; ___t > 1;){
int ___p = ___LinearSieve_Primes::PrimeFactor[ ___t];
int ___k = 0;
while( ___p == ___LinearSieve_Primes::PrimeFactor[ ___t]){
___t /= ___p;
++ ___k;
}
// `___p ^ ___`k;
}
} // 一個數的质因数分解 ($O(1)$)
O ( a ln a ) O( \frac{\sqrt{a}}{ \ln{ \sqrt{a}}}) O(lnaa)(预处理)
性質
實際時間 要更小, 因為這個for循環 大概率不會遍歷所有的[1, sqrt(a)]
裡面的質數, 因為___t
是在不斷的變小的;
代碼
{ // 一個數的质因数分解 ($O( \frac{\sqrt{a}}{ \ln{ \sqrt{a}}})$)
auto ___a = ?;
map< decltype(___a), int> ___Factors; // `a`的質因數分解
auto ___t = ___a;
for( 滿足`___p <= ___t / ___p`的所有*質數*){
int ___k = 0;
while( ___t % ___p == 0){
___t /= ___p;
++ ___k;
}
___Factors[ ___p] = ___k;
}
if( ___t > 1){
___Factors[ ___t] = 1;
}
} // 一個數的质因数分解 ($O( \frac{\sqrt{a}}{ \ln{ \sqrt{a}}})$)