质数
1.质数的判定:
判断一个数n是否为质数,可以用试除法,枚举2到sqrt(n)即可。
bool is_prime(int n) { if(n==1) return false; for(int i=2;i<=sqrt(n);i++) { if(n%i==0) return false; } return true; }
2.质数的筛选
给定一个整数n,求出1到n之间的所有质数,称为质数的筛选问题。
Eratosthenes筛法:任意整数x的倍数都不是质数。
所以我们可以从2开始依次扫描每个数x,把x的倍数都标记为合数,当扫描到一个没有被标记的数时,那该数为质数。
void primes(int n) { memset(v,0,sizeof(v)); for(int i=2;i<=n;i++) { if(v[i]) continue; cout<<i<<endl;//i是质数 for(int j=i+i;j<=n;j+=i) c[j]=1; } }
这样会发现会重复把一个数标记为合数,仔细想想会发现小于x2的x的倍数在扫描更小的时候就被标记过了,
所以可以对Eratosthenes进行优化,对于每个数x,只需要从x2开始遍历就可以了。
void primes(int n) { memset(v,0,sizeof(v)); for(int i=2;i<=n;i++) { if(v[i]) continue; cout<<i<<endl; for(int j=i;j<=n/i;j++) c[i*j]=1; } }
线性筛法:
优化后的Eratosthenes筛法依然会重复标记合数,比如12会被2和3标记,主要的原因是没有唯一确定产生12的方式。
线性筛法是通过从大到小累积质因子的方式标记每个合数,即让12只有3*2*2这一种方式产生。
是数组v记录每个数的最小质因子,按照以下步骤维护v即可。
1:依次考虑2到n之间的每一个数i。
2:如果v[i]=i,说明i是质数,把他保存下来.
3:扫描不大于v[i]的每个质数p,v[i*p]=p。就是在i的基础上累积一个质因子p。
int v[MAX_N],prime[MAX_N]; void primes(int n) { memset(v,0,sizeof(v)); 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++)//给当前的数i乘上一个质因子 { if(prime[j]>v[i]||prime[j]>n/i) break; v[i*prime[j]]=prime[j]; } } for(int i=1;i<=m;i++) cout<<prime[i]<<endl; }
3:质因子分解
任何一个大于1的正整数都能唯一分解为有限个质数的乘积。
将n进行质因子分解可以先用Eratosthenes筛法求出1到n里的素数存入a[i],任何枚举遍历素数即可。