素数筛法

= =素数是一个很重要的块,所以筛法也是灰常重要的

首先 是传统筛法

第一版:

 1 #define MAXN 1000001
 2 bool isprime[MAXN];
 3 long  prime[MAXN];
 4 int cnt;
 5 void getprime()
 6 {
 7     int i,j;
 8     memset(isprime,1,sizeof(isprime));
 9     isprime[0]=isprime[1]=cnt=0;
10     for(i=2;i*i<MAXN;i++)
11     {
12         if(isprime[i])
13         {
14             for(j=i*i;j<MAXN;j+=i)
15             {
16                 if(isprime[j])
17                 {
18                     isprime[j]=false;
19                 }
20             }
21 
22         }
23     }
24     for(i=2;i<MAXN;i++)
25     {
26         if(isprime[i])
27             prime[cnt++]=i;
28     }
29 }

ps:其实我个人感觉这个算法平常的一些题是够用的( ̄ε(# ̄)☆╰╮( ̄▽ ̄///)(快学习!

第二版:

#define MAXN 1000001
bool isprime[MAXN];
long  prime[MAXN];
int cnt;
void getprime()
{
    int i,j;
    memset(isprime,true,sizeof(isprime));
    isprime[0]=isprime[1]=cnt=0;
    for(i=3;i<MAXN;i++)
        prime[i]=i%2==0?0:1;

    for(i=2;i<t;i++)
    {
        if(isprime[i])
        {
            for(j=i*i;j<MAXN;j+=i)
            {
                if(isprime[j])
                {
                    isprime[j]=false;
                }
            }

        }
    }
    for(i=2;i<MAXN;i++)
    {
        if(isprime[i])
            prime[cnt++]=i;
    }
}

相比于第一版,先去除了2以后的偶数,因为这些偶数根本不可能是素数嘛(~ ̄▽ ̄)~,( ̄ε(# ̄)☆╰(废话

嗯,容我测试一下时间= =,额……这时间不稳定!(╯‵□′)╯︵┻━┻ 怎么时间还增加了啊喂

仔细想了想 我们可以把第一版储存素数的数组放入循环,但第二版是不可以的,因为优先判断了偶数和奇数,而且我们可以将i*i<MAXN 判断化为 temp=sqrt(MAXN)+1 ;i<temp 从而避免每次计算i*i 

ps:将储存数组放入循环后,如果你想得到更大的素数需要修改MAXN的值,当然你也可以将储存数组放在外面,下面的算法也均将储存数组放在循环内,但是对于较大值的MAXN,为了效率,我建议使用线性筛法

第三版

 1 #define MAXN 1000000
 2 
 3 long cnt,temp=sqrt(MAXN)+1;
 4 bool isprime[MAXN];
 5 long long prime[MAXN];
 6 
 7 void getprime()
 8 {
 9     int i,j;
10     memset(isprime,1,sizeof(isprime));
11     isprime[0]=isprime[1]=cnt=0;
12     for(i=2;i<temp;i++)
13     {
14         if(isprime[i])
15         {
16             prime[cnt++]=i;
17             for(j=i*i;j<MAXN;j+=i)
18             {
19                 if(isprime[j])
20                 {
21                     isprime[j]=false;
22                 }
23             }
24         }
25     }
26 }

嗯,现在我们再来测测时间……,(╯‵□′)╯︵┻━┻,到底怎么测啊不会啊喂!老是不稳定!( ̄ε(# ̄)☆╰╮( ̄▽ ̄///)(学习!

----------------------------------------------------------------------------------------------------------------------------------------

下面我们试试线性筛法

#define MAXN 1000000
long cnt;bool isprime[MAXN];
long long prime[MAXN];
void x_getprime()
{
    int i,j;
    memset(isprime,1,sizeof(isprime));
    isprime[0]=isprime[1]=cnt=0;
    for(i=2;i<MAXN;i++)//下面循环考虑了超出的情况,所以可以直接使用MAXN
    {
        if(isprime[i])
            prime[cnt++]=i;//与上面一样将储存素数步骤放入循环
        for(j=0;j<cnt&&i*prime[j]<MAXN;j++)//因为这里for循环判断上下均使用i*prime[j]所以我们不将i*prime[j]储存起来,while可以储存试试
        {    
            isprime[i*prime[j]]=false;
            if(!(i%prime[j]))break;//关键点
        }
    }
}

传统的筛法和线性素数筛法的区别是,线性筛法不会筛掉同一个数多次,原因在关键点上下面我们来研究一下线性筛法

首先,筛掉合数:

首先对于一个数num 其能写成 p1*p2(素数*素数)形式 则其肯定第一次被筛掉

若其能 n*p(合数*素数)形式,则其也能写成(p1*p2*……pn)的素数形式,则也筛掉

其次,不重复:

从上面的循环我们可以看出i一定大于等于prime[j],当i=prime[j] 时我们就退出循环

而传统筛法里,6=2*3=3*2是被重复筛掉的,而线性筛法中对于6 我们只进行6=2*3的删除

嗯,以上是今天的的筛法的学习。

参考:http://blog.csdn.net/dinosoft/article/details/5829550  

该网页最后也有一种针对奇数的筛法,但我笔记本快没电了( ̄ε(# ̄)☆╰╮(谁叫你不带电源

所以回去了再看……嗯现在可以去试试TLE的几道题……

原文地址:https://www.cnblogs.com/byzsxloli/p/5397846.html