题目: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素数的倍数