其他相关知识
试除法判定质数
代码如下:
bool is_prime(int n){
if(n < 2) return false;
for(int d = 2; d <= n/d; d ++ ){
//如果d能整除n,那么n为合数
if(n % d == 0) return false;
}
return true;
}
其他相关知识
问题:
给出一个整数N,求1~N之间所有质数
定义
时间复杂度计算
代码如下:
int primes[N],cnt;//存储质数
bool v[N];//标记合数
void get_primes(int n){
for(int i = 2; i <= n; i ++ ){
if(v[i]) continue;
primes[++cnt] = i;
for(int j = i; j <= n/i; j ++) v[j * i] = true;
}
}
思想
问题引入:
Solution
代码如下:
int primes[N],cnt;//存储质数
int v[N];//存储每个数的最小质因子
void get_primes(int n){
cnt = 0;
for(int i = 2; i <= n; i ++ ){
//如果v[i]=0,表示当前数为质数
if(!v[i]) v[i] = i,primes[++cnt] = i;
//从小到大枚举所有已经存储过的质数,让i乘上这些质数
for(int j = 1; j <= cnt; j ++){
//如果当前质数大于i的最小质因子或者i*primes[j]>n就终止
if(primes[j] > v[i] || primes[j] > n/i) break;
//i*primes[j]的最小质因子就是primes[j]
v[i*primes[j]] = primes[j];
}
}
}
算数基本定理
代码如下
int primes[N],cnt;//存储质数
int c[N];//存储质因子的次数
void divide(int n){
cnt = 0;
for(int d = 2; d <= n/i; d ++ ){
//这个d就是n的质因子
if(n % d == 0){
primes[++cnt] = d;
//筛掉所有的d,并记录d出现的次数
while(n%d == 0) n/=d,c[cnt]++;
}
}
//如果n大于1.那么这个数就是唯一一个大于根号n的质因子
if(n > 1) {primes[++cnt] = n,c[cnt] = 1}
}
拓展:PoLLard’s Rho算法
一个比试除法效率更高的质因数分解算法,暂不讨论
约数的定义
算数基本定理的推论
一 、 计 算 N 的 正 约 数 个 数 一、计算N的正约数个数 一、计算N的正约数个数
代码如下:
unordered_map primes;
//first:质因子 second:质因子的次数
for(int i = 2; i <= n/i; i ++ ){
while(n % i == 0){
n/=i;
primes[i]++;
}
}
if(n > 1) primes[n]++;
int res = 1;
for(auto prime:primes) {
res *= (prime.second + 1);
}
二 、 计 算 N 的 所 有 正 约 数 之 和 二、计算N的所有正约数之和 二、计算N的所有正约数之和
代码如下:
unordered_map primes; //first:质因子 second:质因子的次数
for(int i = 2; i <= n/i; i ++ ){
while(n % i == 0){
n/=i;
primes[i]++;
}
}
if(n > 1) primes[n]++;
int res = 1;
for(auto prime:primes) {
int p = prime.first,c = prime.second;
int t = 1;
while(c --) t = t * p + 1;
res *= t;
}
求N的所有正约数
代码如下:
int factor[N],cnt;//存储约数
void get_factor(int n){
for(int d = 1; d <= n/d; d ++ ){
if(n%d == 0){
factor[++cnt] = d;
//如果d*d!=n
if(d != n/d) factor[++cnt] = n/d;
}
}
}
代码如下
vector factor[N];
for(int i = 1; i <= n; i ++ ){
for(int j = 1; j <= n/i; j ++ ){
factor[i * j].push_back(i);
}
}
for(int i = 1; i <= n; i ++ ){
for(int j = 0; j < factor[i].size(); j ++ ){
printf("%d ",factor[i][j]);
}
puts("");
}
最大公约数的定义
最小公倍数的定义
三个数及以上,同理
公式
一、
∀ a , b ∈ N , l c m ( a , b ) = a ∗ b g c d ( a , b ) \forall a,b\in \mathbb{N}, lcm(a,b) = {a*b\over gcd(a,b)} ∀a,b∈N,lcm(a,b)=gcd(a,b)a∗b
公式
一、
∀ a , b ∈ N , a > = b , 有 g c d ( a , b ) = g c d ( b , a − b ) = g c d ( a , a − b ) \forall a,b \in \mathbb{N},a>=b,有gcd(a,b) = gcd(b,a-b)=gcd(a,a-b) ∀a,b∈N,a>=b,有gcd(a,b)=gcd(b,a−b)=gcd(a,a−b)
二、
∀ a , b ∈ N , 有 g c d ( x a , x b ) = x ∗ g c d ( a , b ) \forall a,b \in \mathbb{N},有gcd(xa,xb) =x*gcd(a,b) ∀a,b∈N,有gcd(xa,xb)=x∗gcd(a,b)
证明
a > = b , 对 于 任 意 公 约 数 d , 因 为 d ∣ a , d ∣ b , a = [ a d ] ∗ d , b = [ b d ] ∗ d , a − b = ( [ a d ] − [ b d ] ) ∗ d , 所 以 d ∣ ( a − b ) . 因 此 , a , b 公 约 数 集 合 与 b , a − b 公 约 数 集 合 相 同 , a , a − b 同 理 a>=b,对于任意公约数d,因为d|a,d|b,a = [{a\over d}]* d,b = [{b\over d}]*d,a-b =([{a\over d}] - [{b\over d}])*d ,所以d|(a-b).因此,a,b公约数集合与b,a-b公约数集合相同,a,a-b同理 a>=b,对于任意公约数d,因为d∣a,d∣b,a=[da]∗d,b=[db]∗d,a−b=([da]−[db])∗d,所以d∣(a−b).因此,a,b公约数集合与b,a−b公约数集合相同,a,a−b同理
公式
∀ a , b ∈ N , b ≠ 0 , g c d ( a , b ) = g c d ( b , a m o d b ) \forall a,b \in \mathbb{N},b\neq 0,gcd(a,b) = gcd(b,a\mod b) ∀a,b∈N,b=0,gcd(a,b)=gcd(b,amodb)
证明
这 里 需 要 分 类 讨 论 a 和 b 的 大 小 情 况 这里需要分类讨论a和b的大小情况 这里需要分类讨论a和b的大小情况
关于两种求最大公约数的方法
欧几里得算法实现
int gcd(int a,int b){
//当b=0时,gcd(a,0)=a
if(!b){
return a;
}
else{
return gcd(b,a%b);
}
}
前置知识:互质
∀ a , b ∈ N , 若 g c d ( a , b ) = 1 , 则 称 为 a 和 b 互 质 , 对 于 三 个 及 以 上 个 数 , g c d ( a , b , c ) = 1 叫 做 a 、 b 和 c 互 质 , g c d ( a , b ) = g c d ( b , c ) = g c d ( a , c ) 叫 a , b , c 两 两 互 质 。 \forall a,b \in \mathbb{N},若gcd(a,b) = 1,则称为a和b互质,对于三个及以上个数,gcd(a,b,c) = 1叫做a、b和c互质,gcd(a,b) = gcd(b,c) = gcd(a,c) 叫a,b,c两两互质。 ∀a,b∈N,若gcd(a,b)=1,则称为a和b互质,对于三个及以上个数,gcd(a,b,c)=1叫做a、b和c互质,gcd(a,b)=gcd(b,c)=gcd(a,c)叫a,b,c两两互质。
欧拉函数的定义
1 ~ N 中 与 N 互 质 数 的 个 数 叫 欧 拉 函 数 , 记 为 ϕ ( N ) 1~N中与N互质数的个数叫欧拉函数,记为\phi (N) 1~N中与N互质数的个数叫欧拉函数,记为ϕ(N)
公式:
依 据 算 术 基 本 定 理 , 若 N = p 1 c 1 p 2 c 2 . . . p k c k , 则 依据算术基本定理,若N=p_1^{c_1}p_2^{c_2}...p_k^{c_k},则 依据算术基本定理,若N=p1c1p2c2...pkck,则
ϕ ( N ) = N ∗ p 1 − 1 p 1 ∗ p 2 − 1 p 2 ∗ . . . ∗ p k − 1 p k = N ∗ ∏ 质 数 p ∣ N ( 1 − 1 p ) \phi(N) = N * {p_1-1 \over {p_1}} * {p_2-1 \over {p_2}} *...*{p_k-1 \over {p_k}} = N *\prod_{质数p|N}(1 - {1\over p}) ϕ(N)=N∗p1p1−1∗p2p2−1∗...∗pkpk−1=N∗∏质数p∣N(1−p1)
证明:
用 到 了 容 斥 原 理 , 参 考 《 算 法 进 阶 指 南 》 上 的 证 明 , 设 p 、 q 是 N 的 质 因 子 , 1 到 N 中 p 的 倍 数 有 [ N / p ] 个 , 用到了容斥原理,参考《算法进阶指南》上的证明,设p、q是N的质因子,1到N中p的倍数有[N/p]个, 用到了容斥原理,参考《算法进阶指南》上的证明,设p、q是N的质因子,1到N中p的倍数有[N/p]个,
同 理 , q 的 倍 数 有 [ N / q ] 个 , 剩 下 的 有 N − [ N / p ] − [ N / q ] 个 , 但 是 这 里 把 p 和 q 的 倍 数 减 去 两 次 ( p 的 倍 数 一 次 , q 的 倍 数 一 次 ) , 需 要 加 上 那 么 结 果 为 N − N p − N q + N p q = N ∗ ( 1 − 1 p ) ∗ ( 1 − 1 q ) , 同 理 得 出 全 部 与 N 互 质 的 个 数 。 同理,q的倍数有[N/q]个,剩下的有N-[N/p]-[N/q]个,但是这里把p和q的倍数减去两次(p的倍数一次,q的倍数一次),需要加上那么结果为N-{N\over p}-{N\over q} + {N\over pq} = N*(1-{1\over p})*(1-{1\over q}),同理得出全部与N互质的个数。 同理,q的倍数有[N/q]个,剩下的有N−[N/p]−[N/q]个,但是这里把p和q的倍数减去两次(p的倍数一次,q的倍数一次),需要加上那么结果为N−pN−qN+pqN=N∗(1−p1)∗(1−q1),同理得出全部与N互质的个数。
代码如下:
int phi(int n){
int ans = n;
for(int i = 2; i <= n/i; i ++ ){
if(n % i == 0){
ans = ans/i*(i - 1);
while(n % i == 0) n/=i;
}
}
if(n > 1) ans = ans/n*(n - 1);
return ans;
}
埃氏筛法求欧拉函数
int primes[N],cnt;//存储质数
int phi[N];//phi[i]:表示i的欧拉函数
void euler(int n){
//1的欧拉函数是1
phi[1] = 1;
for(int i = 2; i <= n; i ++ ) phi[i] = i;
for(int i = 2; i <= n; i ++ ){
//i是质数
if(phi[i] == i){
//对于j,多个i质因子
for(int j = i; j <= n; j += i){
phi[j] = phi[j]/i*(i - 1);
}
}
}
}
线性筛法求欧拉函数
若 i m o d p j = = 0 , ϕ ( i ∗ p j ) = ϕ ( i ) ∗ p j 若i\mod pj == 0,\phi(i*pj) = \phi(i)*pj 若imodpj==0,ϕ(i∗pj)=ϕ(i)∗pj
否 则 , ϕ ( i ∗ p j ) = ϕ ( i ) ∗ p j ∗ ( 1 − 1 p j ) = ϕ ( i ) ∗ ( p j − 1 ) 否则,\phi(i*pj) = \phi(i)*pj*(1-{1\over pj}) = \phi(i)*(pj - 1) 否则,ϕ(i∗pj)=ϕ(i)∗pj∗(1−pj1)=ϕ(i)∗(pj−1)
int primes[N],cnt;//存储质数
int st[N];//st[i]:i的最小质因子
int phi[N];//phi[i]:表示i的欧拉函数
void euler(int n){
for(int i = 2; i <= n; i ++ ){
if(!st[i]) st[i] = i,primes[++cnt] = i,phi[i] = i - 1;
for(int j = 1; j <= cnt; j ++ ){
if(primes[j] > st[i] || primes[j] > n/i) break;
//i*primes[j]的最小质因子primes[j]
st[i*primes[j]] = primes[j];
//如果primes[j]是i的最小质因子,说明i*primes[j]已经有这个质因子
if(i % primes[j] == 0){
phi[i*primes[j]] = phi[i] * primes[j];
}else{
//primes[j]是新成员
phi[i*primes[j]] = phi[i] * (primes[j] - 1);
}
}
}
}
后记:以上笔记是本人参考《算法进阶指南》书籍以及之前所学总结而得,如果知识不完善或者有误,请各位指点。如果对您有帮助,点赞,关注共同进步