POJ 2689 Prime Distance【求不超时】

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

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

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

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

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

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

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

//4268K	47MS
#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];
			else
				begin = 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");
		else
			printf("%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素数的倍数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值