[数论]素数相关整理

1-n之间有多少个素数

10的1次方        4
10的2次方        25
10的3次方        168
10的4次方        1229
10的5次方        9592
10的6次方        78498
10的7次方        664579
10的8次方        5761455
10的9次方        50847534

1.单独判断一个数是否为素数

bool prime(int n)
{
    if(n==0||n==1) return false;
    if(n==2) return true;
    for(int i=2;i<=sqrt(n);i++)
        if(n%i==0)
            return false;
    return true;
}

2.筛法筛素数 ,求小于maxn的素数

isprime[ ] 保存小于maxn的数是否为素数,false表示不是素数,true表示素数

prime[ ] 保存小于maxn的素数有哪些,从0开始,长度为len

const int maxn=100;
bool isprime[maxn];
int prime[maxn];
int len=0;

void sieve(int n)
{
    for(int i=0;i<n;i++)
        isprime[i]=1;
    isprime[0]=isprime[1]=0;
    for(int i=2;i<n;i++)
        if(isprime[i])
        {
            prime[len++]=i;
            for(int j=2*i;j<n;j+=i)
                isprime[j]=0;
        }
}
//主函数调用sieve(maxn)

3.如果只要求小于maxn的素数有哪些,去掉isprime[ ]数组

下面模板中 prime[ ] 中保存的是maxn中的素数有哪些,标号从1开始,总的素数个数为prime[0] ,它包含的素数范围为 prime[1]到prime[  prime[0] ] 

const int maxn=100;
int prime[maxn+1];

void getPrime()
{
    memset(prime,0,sizeof(prime));//一开始prime都设为0代表都是素数(反向思考)
    for(int i=2;i<=maxn;i++)
    {
        if(!prime[i])
            prime[++prime[0]]=i;
        for(int j=1;j<=prime[0]&&prime[j]<=maxn/i;j++)
        {
            prime[prime[j]*i]=1;//prime[k]=1;k不是素数
            if(i%prime[j]==0)
                break;
        }
    }
}


4.大区间筛素数

POJ:2689 

给出一个区间[L,R], 范围为1<=L< R<=2147483647,区间长度长度不超过1000000

求距离最近和最远的两个素数(也就是相邻的差最小和最大的素数)

筛两次,第一次筛出1到1000000的素数,因为1000000^2已经超出int范围,这样的素数足够了。

函数getPrim();   prime[ ] 存第一次筛出的素数,总个数为prime[0] 

第二次利用已经筛出的素数去筛L,R之间的素数

函数getPrime2();     isprime[] 判断该数是否为素数 prime2[ ]筛出的素数有哪些,一共有prime2[0]个

模板:

#include <iostream>
#include <string.h>
#include <stdio.h>
#include <cmath>
#include <algorithm>
using namespace std;

const int maxn=1e6;
int prime[maxn+10];

void getPrime()
{
    memset(prime,0,sizeof(prime));//一开始prime都设为0代表都是素数(反向思考)
    for(int i=2;i<=maxn;i++)
    {
        if(!prime[i])
            prime[++prime[0]]=i;
        for(int j=1;j<=prime[0]&&prime[j]<=maxn/i;j++)
        {
            prime[prime[j]*i]=1;//prime[k]=1;k不是素数
            if(i%prime[j]==0)
                break;
        }
    }
}

bool isprime[maxn+10];
int prime2[maxn+10];

void getPrime2(int L,int R)
{
    memset(isprime,1,sizeof(isprime));
    //isprime[0]=isprime[1]=0;//这句话不能加,考虑到左区间为2的时候,加上这一句,素数2,3会被判成合数
    if(L<2) L=2;
    for(int i=1;i<=prime[0]&&(long long)prime[i]*prime[i]<=R;i++)
    {
        int s=L/prime[i]+(L%prime[i]>0);//计算第一个比L大且能被prime[i]整除的数是prime[i]的几倍,从此处开始筛
        if(s==1)//很特殊,如果从1开始筛的话,那么2会被筛成非素数
            s=2;
        for(int j=s;(long long)j*prime[i]<=R;j++)
            if((long long)j*prime[i]>=L)
            isprime[j*prime[i]-L]=false; //区间映射 ,比如区间长度为4的区间[4,7],映射到[0,3]中,因为题目范围2,147,483,647数组开不出来
    }
    prime2[0]=0;
    for(int i=0;i<=R-L;i++)
        if(isprime[i])
        prime2[++prime2[0]]=i+L;
}

int main()
{
    getPrime();
    int L,R;
    while(scanf("%d%d",&L,&R)!=EOF)
    {
        getPrime2(L,R);
        if(prime2[0]<2)
            printf("There are no adjacent primes.\n");
        else
        {
            //for(int i=1;i<=prime2[0];i++)
               // cout<<prime2[i]<<endl;
            int x1=0,x2=1000000,y1=0,y2=0;
            for(int i=1;i<prime2[0];i++)
            {
                if(prime2[i+1]-prime2[i]<x2-x1)
                {
                    x1=prime2[i];
                    x2=prime2[i+1];
                }
                if(prime2[i+1]-prime2[i]>y2-y1)
                {
                    y1=prime2[i];
                    y2=prime2[i+1];
                }
            }
            printf("%d,%d are closest, %d,%d are most distant.\n",x1,x2,y1,y2);
        }
    }
    return 0;
}




你可能感兴趣的:(素数,数论,ACM)