英雄会(csdn pongo)题解之半质数的个数--2·14情人&元宵节专题

来源:互联网 发布:mcs51单片机编程环境 编辑:程序博客网 时间:2024/05/30 23:41
题目详情

质数是大家熟知的概念,我们定义一个半质数的概念:如果一个数恰好是两个质数的乘积(可以相同),则称它为半质数。前几个半质数是 4, 6, 9, 10, 14, 15, 21, 22, 25, 26。我们的问题是,输入两个正整数x<=y,问[x,y]之间有多少个半质数?

输入:x,y

输出:[x,y]之间有多少个半质数。

输入数据范围 1<=x<=y<=2000000。

1.我的做法:

需要明白

(1)两个质数的乘积不等于其他任何两个质数的乘积,因为c=a×b,a,b为质数,那么c的所有因子为1,a,b,a×b,所以c不等于任何其他两个质数的乘积。

也就是说只要两个质数的乘积在[x,y]区间内,那么我们所求的结果就要加1,因为两个质数的乘积不会重复。

(2)某个质数的平方如果大于y,那么这个质数与比他大的质数的乘积肯定大于y。

根据上面两条得出以下做法:

prime保存的是从小到大的质数;

求得y的平方根sy(对下取整),找到小于sy且最接近的质数,赋值给sy,如果不存在这样的质数,返回结果0;

for(sx=2;sx<=sy,sx=下一个质数){

       从第i个质数开始,sx与prime[i]乘积大于等于x;

       到第j个质数为止,sx与prime[j]乘积小于等于y;

       结果+=j-i+1;

}

返回结果


2.我的质数打表方法:

我用两个数组来实现打表:

第一个数组num[2000001]保存的是比本数组下标小且最接近的质数在第二个数组中的下标;

第二个数组prime[]依次保存的是2000000内的质数(从小到大)。

为了便于使用,多分配一个空间,第0个元素不使用,从第一个元素开始。且num[1]=-1,图示如下,打表代码见下面:


这样易于找到比某个数小且最接近的质数,且容易得到这个质数是第几个质数;

如比i小且最接近的质数是prime[num[i]], 这个质数是第num[i]个质数,便于程序计算结果。

当然这里可以用筛法进行优化。

3.C++代码如下:

#include <stdio.h>#include <iostream>#include <string>#include <cmath>#include <ctime>using namespace std;#define MAX 2000000class Test {public:    static int* num;    static int* prime;    static bool isPrime(int i){//判断是否是质数        if(i<2)return false;        if(2==i)return true;        int s=(int)sqrt(double(i));        for(int j=2;j<=s;++j){            if(0==i%j) return false;        }        return true;    }    static int comp(int x,int y){if(y<=3)return 0;        int res=0;int sx=2;int sy=prime[num[(int)sqrt((double)y)]];        if(sy<=1)return 0;        while(sx<=sy){ int tmpX=x/sx;if(tmpX<=1)tmpX=2;//2跟num数组有关,前两个存储的不是质数数组的索引int indexX=num[tmpX]>num[sx]?num[tmpX]:num[sx];while(sx*prime[indexX]<x)++indexX;int tmpY=y/sx;if(tmpY>=2)//2跟num数组有关,前两个存储的不是质数数组的索引if(num[tmpY]>=indexX)res+=num[tmpY]-indexX+1;            sx=prime[num[sx]+1];        }        return res;    }    static int howmany (int   x,int   y){//第一次调用函数,进行质数打表        static bool firstTime=true;        if(firstTime){            firstTime=false;//为了每次取数组元素时,不进行-1操作,多分配一个空间,不使用第0个            num=new int[MAX+1];            prime=new int[150001];            num[1]=-1;//1            num[2]=1;//2            prime[1]=2;            int pNum=1;            for(int i=3;i<=MAX;++i)                if(isPrime(i)){                    num[i]=++pNum;                    prime[pNum]=i;                }else                    num[i]=pNum;          }        return comp( x,y);    }};int*Test::num;int*Test::prime;//start 提示:自动阅卷起始唯一标识,请勿删除或增加。int main(){        clock_t t1=clock(); cout<<Test::howmany(1,2)<<endl; cout<<Test::howmany(1,30)<<endl;    cout<<Test::howmany(6,30)<<endl;   cout<<Test::howmany(6,2000000)<<endl;      cout<<Test::howmany(1,4)<<endl;    clock_t t2=clock();    std::cout<<(t2-t1)/(double)CLOCKS_PER_SEC<<std::endl;    } //end //提示:自动阅卷结束唯一标识,请勿删除或增加。

4.时间复杂度为O(√y)

0 0
原创粉丝点击