您的位置:首页 > 其它

素数判定 & 素数筛法 & poj_3292_Semi-prime H-numbers

2014-08-06 22:20 357 查看
数论周:

学了几个小东西,这里讲一下找素数。

素数:一个大于1的自然数,除了1和它本身外,不能被其他自然数整除(除0以外)的数称之为素数(质数);否则称为合数。

根据这个性质,判断一个数 n 是否为素数 ,我们可以从 2 ~ n-1 找是否有其因子,如果有,则说明不是素数,return false;反之,return true;

又因为一个数有个小于 sqrt(n)的因子,则一定有一个大于 sqrt(n),反之,如果在 2 ~ sqrt(n)里面没有找到一个因子,那么在sqrt(n)后面也不会有。

bool isprime (int n){
    for (int i=2;i*i<=n;i++)
        if (n%i==0)
            return false;
    return true;
}


很方便的判断是否为素数。但如果要进行非常多次判断的话,这种方法将将不再适用,我们要寻求一种更加快速的方法。

因为每个素数只有1和它本身两个因子,所以一个素数的倍数一定不是素数。比如,已知 k 是一个素数,则大于 k 的倍数都不是素数。因此,我们可以把这些数标记成0;

则下次将不再判断。接下来的第一个标记为1的数一定是素数,因为比他小的数的倍数都已经标记完了。

两个优化:

1:在筛除 素数 k 的倍数时,从 k 的 k 倍开始。因为对于 k 的 v (v<k)倍,k*v 一定会在筛除 v 的倍数时 被筛除。

2:由于1的正确性,在枚举已知素数 k 时,只需要枚举到 sqrt(n)的时候,就可以了。

因为当 k > sqrt(n)时, 根据 1中所述,将进行筛除 > n的非素数,这些操作是非必要的。

bool isp[1000000];
void isprime (int n){
    memset (isp,true,sizeof(isp));
    isp[0]=isp[1]=false;
    for (int i=2;i*i<n;i++){
        if (isp[i]){
            int j=i;
            while (j*i<n){
                isp[j*i]=false;
                j++;
            }
        }
    }
}


来道例题,最近做的素数的题比较少,这是一道“伪”素数:

poj_3292_Semi-prime H-numbers

题目给出一个集合 E 4*n+1 (n是自然数)。里面的数叫作 H-number 。数 H-primes 是在 E 中没有出1和它本身的约数的数,(类似素数)。

给出一个数 n ,求 n 以内有多少数是可以有两个H-primes相乘得到的。

我们可以用类似素数筛法的方法找出所有的 H-primes :5, 9, 13, 17...然后让它们两两想乘,得到数k , v [ k ] 标记成1;然后再用一个数组统计 ans[ k ] k以内有多少这样的数。

/*
 *水水更健康
 */
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long llint;
llint ishp[10000020];
llint vhp[10000020];
llint ans[10000020];
llint hp[100000];

void sushu(){
    ishp[0]=1;ishp[1]=0;
    for (llint i=5;i*i<1000010;i+=4){
        if (ishp[i]==0){
            llint j=i;
            while (j*i<1000002){
                ishp[i*j]=1;
                j+=4;
            }
        }
    }
    llint k=0;
    for (llint i=0;i<1000002;i++){
        if (ishp[i]==0&&i%4==1){
            hp[k++]=i;
//            printf ("%d ",hp[k-1]);getchar();
        }
    }
    for (llint i=1;i<k;i++){
        for (llint j=i;j<k;j++){
            if (hp[i]*hp[j]<1000002){
                vhp[hp[i]*hp[j]]=1;
            }
            else break;
        }
    }
    llint a=0;
    for (llint i=0;i<=1000001;i++){
        if (vhp[i]==1)
            a++;
        ans[i]=a;
    }
}

int main(){
    llint n;sushu();
    while (scanf ("%I64d",&n)!=EOF&&n){
        printf ("%I64d %I64d\n",n,ans
);
    }
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: