您的位置:首页 > 其它

uva_10140/poj_2689 Prime Distance(區間素數)

2015-06-27 20:17 330 查看
uva 題目鏈接:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=35&page=show_problem&category=13&problem=1081&mosmsg=Submission+received+with+ID+15689014

題目大意:在給定範圍L和R,找到L和R範圍內差距最小和最大的兩對素數。1=< L<=R<=2,147,483,647,R-L<=1000000

分析:

區間素數,經典問題。因為最大是2^31-1,開根號為小於46341,所以可以先預處理做一遍素數篩選,篩出1~50000的素數,然後再用1~50000的素數去篩選任意L到R之間的素數。具體做法,可開一個a[]存所求區間的素數情況,求a[L]~a[R]之間的素數,就是求a[0]~a[R-L]之間的素數。

代碼:

#include<cstdio>
#include<cstdlib>
#include<cstring>
using namespace std;
#define range 50000
#define range2 1000010
#define INF 0xFFFFFFF
typedef long long LL;
int prime[range],is_prime[range];
int a[range2],prime2[range2];
int num_p;
void produce_prime()
{
memset(is_prime,0,sizeof(is_prime));
num_p=0;
for(int i=2;i<range;i++)
{
if(is_prime[i]==0)
{
int j=i+i;
prime[num_p++]=i;
while(j<range)
{
is_prime[j]=1;
j+=i;
}
}
}
}
int main()
{
//  freopen("in.txt","r",stdin);
LL left,r;
produce_prime();//預處理先篩出50000以內的素數
while(scanf("%lld%lld",&left,&r)==2)//這裡如果用%d%d,在poj上會TLE,但是在uva上能AC
{
memset(a,0,sizeof(a));
if(left==1)
{
a[0]=1;  //如果L=1,它不能算做素數,此處特判
}
for(int i=0;i<num_p && prime[i]*prime[i]<=r;i++)//從最小的素數開始,循環要小於素數個數和小於R的開根號
{
int k=(int)left/prime[i];//從prime[i]的倍數開始篩,並且這個倍數要大於等於left,k為prime[i]的幾倍
LL m=k*prime[i];
while(m<left || k<=1) //因為k是整除得來,所以如果left不是prime[i]的整數倍,多餘的部分就會被去掉,或者出現left<prime[i]的情況;還有就是正好left是素數,k=1,此時left不能被篩掉,所以要讓k>1而且m>=k
{
m+=(LL)prime[i];
k++;
}
for(LL j=m;j<=r;j+=prime[i])
{
if(j>=left)//開始用素數篩,將left~r中prime[i]的倍數篩掉,因為left,r可能很大,這裡用了一個**偏移的index**的技巧,即a[j]=1等價于a[j-left]=1,篩選時將所有a[left]~a[r]==a[0]~a[r-left]
a[j-left]=1;
}
}
int minn=INF,maxx=-1;
int minflag=-1,minf=-1,minlast=-1,maxf=-1,maxlast=-1,pre=-1;
for(LL i=left;i<=r;i++)
{
if(a[i-left]==0)//這裡一樣,也是用偏移index去判斷是否被篩出
{
if(pre==-1)
{
pre=i;
}
else
{
if(i-pre<minn)
{
minf=pre; minlast=i;
minn=i-pre;
}
if(i-pre>maxx)
{
maxf=pre; maxlast=i;
maxx=i-pre;
}
pre=i;
}
//last=i;
}
}
if(minf==-1)
printf("There are no adjacent primes.\n");
else
printf("%d,%d are closest, %d,%d are most distant.\n",minf,minlast,maxf,maxlast);
}
return 0;
}


關於質數的一些重要結論:

設pi(n)為小於等於n的質數個數,則pi(n)\approxn/n/ln(n)

當n在10^5到10^6左右時,質數的數量大概可以用10/n來估計。

第 n 個質數大約是 nln(n)

《计算机算法导引: 设计与分析》有講到質數的這部分

另外一種求大範圍質數的方法:

http://www.jiancool.com/article/50042575894/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  算法