POJ 2689 Prime Distance【求不超时】

来源:互联网 发布:最好用的纹身单片机 编辑:程序博客网 时间:2024/06/05 02:21

题目:http://poj.org/problem?id=2689

题意:输入个区间,求区间中相邻素数中距离最近和最远的素数

直接筛选法求素数?恭喜你,开21E大的数组,放弃吧

打素数表?数组一样很大,而且素数超多,代码全是素数且还得考虑打表要等几个小时

可行方法:栈的思路,求出区间第1个素数,赋值给临时变量temp,遍历区间,没遇到素数,就和temp求差...

问题主要是遍历区间求素数会超时,我本来想过某个值(如1000W)以下的正常操作,以上的用筛选法判断。不是很可行,还是数组大小问题。

所以采取叠加筛选法,先筛选出一部分(如5W以下的的素数),再根据这些素数筛选区间内的数。

//4268K47MS#include <stdio.h>#include <string.h>#define l_l __int64#define PMAX 50000#define P2_LEN 1000005//区间范围决定int prime[PMAX+1]={0};int p1[PMAX];int p2[P2_LEN];l_l getPrime(){//prime[i]==0为素数    l_l i,len;    l_l t;len = 0;    for(i = 2; i *i <= PMAX; i++)    {        if(!prime[i]){for(t = 2*i; t<= PMAX; t+=i)prime[t] = 1;}}for(i=2;i<PMAX;i++){if(!prime[i]){p1[len++] = i;//存放5W以下素数}}return len;}int main(){l_l i,j,len,max,min,temp,cha,k;l_l t,begin,add;l_l m1,m2,m3,m4;l_l l,r;//freopen("in.txt","r",stdin);len = getPrime();while(~scanf("%I64d %I64d",&l,&r)){min = 2147483649;max = 0;temp = 0;j=0;i=0;memset(p2,0,sizeof(p2));for(k = 1; k< len; k++)//先忽略了2{if(r < p1[k] * p1[k])break;if(l % p1[k])//区间内第1个p1[k]的倍数begin = (l / p1[k] + 1) * p1[k];elsebegin = l;//刚好整除就是左区间点了if( begin % 2 == 0 ){//是偶数再加,偶数+奇数(素数一定是奇数)=奇数p2[begin-l] = 1;//偶数不是素数begin += p1[k];}if(begin < p1[k]*p1[k])begin = p1[k]*p1[k];for(t = begin,add = p1[k]*2; t<= r; t+=add){p2[t-l] = 1;//筛选}}if(l == 2 || l == 1){//特殊处理temp = 2;i = 2;}else{//找出区间内第1个素数i = l;while( p2[i-l] || !(i&1) && i != 2){//偶数肯定不是i++;if(i>r){break;}}}temp = i;//类似于栈顶元素for(++i; i <= r; i++){if(!(i&1) && i != 2)//排除偶数continue;if(!p2[i-l]){cha = i - temp;if( cha > max){m1 = temp;m2 = i;max =  cha;}if( cha < min){m3 = temp;m4 = i;min =  cha;}temp = i;}}if(max == 0 )printf("There are no adjacent primes.\n");elseprintf("%I64d,%I64d are closest, %I64d,%I64d are most distant.\n",m3,m4,m1,m2);}return 0;}


prime[i]:筛选5W以下的素数,值为0表示素数,为1为合数

p1[i]:存放5W以下的素数,值为那个素数

p2[i]:标记 i 是不是素数,也是筛选法的,值为0表示是素数

begin:区间内最小的(第1个)p1素数的倍数

0 0