质数(学习笔记)
质数的判定(时间复杂度\(O(\sqrt{n})\))
bool is_prime(int n){
for(int i=2;i*i<=n;i++)
if(n%i==0) return false;
return true;
}
质数的筛选
给定一个整数N,求出1~N之间的所有质数,称为质数的筛选问题.
Eratosthenes筛选法(时间复杂度O(N))
基本思想:质数的倍数一定不是质数;
void primes(int n){
memset(v,0,sizeof(v)); //先假设全都是质数
for(int i=2;i<=n;i++){
if(v[i]) continue; //如果v[i]=1,i是合数
cout<<i<<endl;
for(int j=i;j<=n/i;j++) v[i*j]=1;
}
}
线性筛法(一定掌握这个)
基本思想:我们在生成一个需要标记的合数时,每次向现有的数乘上一个质因子,并且让它是这个合数的最小质因子.
v数组记录每个数的最小质因子;
int v[N],prime[N];
void primes(int n){
memset(v,0,sizeof(v));
int m=0; //统计质数数量
for(int i=2;i<=n;i++){
if(v[i]==0){ //i是质数
v[i]=i;
prime[++m]=i;
}
for(int j=1;j<=m;j++){
if(prime[j]>v[i]||prime[j]>n/i)
break;
//i有比prime[j]更小的质因子,或者超出n的范围
v[i*prime[j]]=prime[j];
//prime[j]是合数i*prime[j]的最小质因子
}
}
for(int i=1;i<=m;i++)
cout<<prime[i]<<endl;
}
质因数分解
算术基本定理:任何一个大于1的正整数都能唯一分解为有限个质数的乘积,可写作:\(N=p_1^{c_1}p_2^{c_2}…p_m^{c_m}\)(其中ci都是正整数,pi都是质数,且满足p1<p2<p3……<pm)
void divide(int n){
int m=0;//m记录正整数n的质因数的个数
for(int i=2;i*i<=n;i++){
if(n%i==0){ //i是质数
p[++m]=i; //p[]数组记录质因数
c[m]=0; //c[]数组记录质因数的幂
while(n%i==0){
n=n/i;
c[m]++;
}
}
}
if(n>1){ //最后如果n不等于1,它一定是个质数
p[++m]=n;
c[m]=1;
}
for(int i=1;i<=m;i++)
cout<<p[i]<<'^'<<c[i]<<endl;
}
算术基本定理:\(N=p_1^{c_1}p_2^{c_2}…p_m^{c_m}\)
算数基本定理的推论:
N的正约数集合可写作:\({p_1^{b_1}p_2^{b_2}…p_m^{b_m}}\),其中0<=bi<=ci.
N的正约数个数为:\((c_1+1)*(c_2+1)*...*(c_m+1)=\prod_{i=1}^m(c_i+1)\)
N的所有正约数的和为:\((1+p_1+p_1^2+...+p_1^{c_1})*...*(1+p_m+p_m^2+...+p_m^{c_m})\),等价于\(\prod_{i=1}^m(\sum_{j=0}^{c_i}(p_i)^j)\)