一.定义
质数又称素数。一个大于1的自然数,除了1和它自身外,不能被其他自然数整除的数叫做质数;否则称为合数。
对于一个足够大的整数N,不超过N的质数大约有N / ln N 个。
二.质数的判定
试除法:
若一个正整数 N 为合数,则存在一个能整出 N 的数 T ,其中2 <= T <= √N。
bool prime(int n)
{
for(int i=2;i<=sqrt(n);i++)
if(n % i == 0) return false;
return true;
}
三.质数的筛选
Eratosthenes筛法
//Eratosthenes筛法 O(N log logN)
#include
const int Max=10010;
int n;
int vis[Max];
using namespace std;
int main()
{
scanf("%d",&n);
for(int i=2;i<=n;i++)
{
if(vis[i]) continue;
cout<
看代码应该就能懂了。。。
线性筛
简单说就是在生成一个需要标记的合数时,每次只向现有的数中乘上一个质因子,并且让它是这个合数的最小质因子。这相
当于让合数的质因子总小到大累计,即让 12 只有 3*2*2 一种产生方式,比上面Eratosthenes筛法更优秀。
//线性筛 O(N)
#include
const int Max=10010;
int n,tot;
int v[Max],ans[Max]; // v 数组记录每个数的最小质因子
int main()
{
scanf("%d",&n);
for(int i=2;i<=n;i++)
{
if(!v[i])
{
ans[++tot]=i;
v[i]=i;
}
for(int j=1;j<=tot;j++)
{
if(v[i] < ans[j] || ans[j] > n/i) break;
v[i * ans[j]]=ans[j];
}
}
for(int i=1;i<=tot;i++) printf("%d ",ans[i]);
return 0;
}
四.质因子分解
基本定理
任何一个大于 1 的正整数都能唯一分解为有限个质数的乘积,可写作:
N = p1^c1 * p2^c2 * ...... pm^cm
其中 ci 都是正整数, pi 都是质数,且满足 p1
试除法
inline void divide(int n)
{
m = 0;
for(int i = 2;i <= sqrt(n);i++)
{
if(n % i == 0) //i是质数
{
p[++m] = i,c[m] = 0;
while(n % i == 0) n /= i,c[m]++;
}
}
if(n > 1) //n是质数
{
p[++m] = n,c[m] = 1;
}
for(int i = 1;i <= n;i++) cout<
【例题】Prime Distance POJ2689
给定两个整数L,R(1 <= L < R <=2^31 , R-L <= 10^6),求闭区间[L,R]中相邻两个质数的差最大和最小是多少,分别
输出这两个数。
解析:
首先暴力求出[1,R]中所有质数是不可能的,但是R-L得范围很小,并且任何一个合数必定包含一个不超过√N 的质因子。
所以我们只需要筛出2 —— √R 之间的所有质数(可预处理)。对于每个质数 p ,把[L,R]中能被 p 整除的数标记为合数,
未被标记的为质数,再两两比较即可。
代码:
#include
#include
#include
#include
using namespace std;
const int Max=1000100;
int l,r,tot,sum;
int min1,min2,max1,max2;
int num[Max],v[Max],ans[Max];
inline void pre() //预处理
{
memset(v,1,sizeof(v));
for(int i=2;i<=46340;i++)
{
if(v[i])
{
num[++tot]=i;
for(int j=2;j<=46340/i;j++) v[i*j]=0; //√2^31 ≈46340
}
}
}
int main()
{
pre();
while(scanf("%d%d",&l,&r)!=EOF)
{
memset(v,1,sizeof(v));
if (l == 1) l=2; //l = 1 时需特判
for(register int i=1;i<=tot;i++)
for(register int j=l/num[i];j<=r/num[i];j++)
if(j>1) v[num[i] * j - l]=0;
sum = 0;
for(int i=l;i<=r;i++)
{
if(v[i-l]) ans[++sum]=i;
if(i==r) break; //一定要有这个判断!不然 i 可能会达倒 int 最大值然后爆掉。。。
}
int t1=2147483647,t2=0;
for(int i=2;i<=sum;i++)
{
if(ans[i]-ans[i-1] > t2)
{
t2=ans[i]-ans[i-1];
max1=ans[i-1];
max2=ans[i];
}
if(ans[i]-ans[i-1] < t1)
{
t1=ans[i]-ans[i-1];
min1=ans[i-1];
min2=ans[i];
}
}
if(!t2) printf("There are no adjacent primes.\n");
else printf("%d,%d are closest, %d,%d are most distant.\n",min1,min2,max1,max2);
}
return 0;
}