码迷,mamicode.com
首页 > 其他好文 > 详细

uva_10140/poj_2689 Prime Distance(區間素數)

时间:2015-06-28 09:59:19      阅读:141      评论:0      收藏:0      [点我收藏+]

标签:算法

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/

uva_10140/poj_2689 Prime Distance(區間素數)

标签:算法

原文地址:http://blog.csdn.net/xyinktw/article/details/46663721

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!