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

NEFU 2 - 猜想 - [筛法求素数]

时间:2017-09-22 00:57:04      阅读:164      评论:0      收藏:0      [点我收藏+]

标签:秘书   can   cstring   ==   直接   朴素   input   c代码   使用   

题目链接:http://acm.nefu.edu.cn/JudgeOnline/problemShow.php?problem_id=2

Time Limit:3000ms  Memory Limit:65536K

Description

哥德巴赫(Goldbach ]C.,1690.3.18~1764.11.20)是德国数学家;出生于格奥尼格斯别尔格(现名加里宁城);曾在英国牛津大学学习;原学法学,由于在欧洲各国访问期间结识了贝努利家族,所以对数学研究产生了兴趣;曾担任中学教师。1725年,到了俄国,同年被选为彼得堡科学院院士;1725年~1740年担任彼得堡科学院会议秘书;1742年,移居莫斯科,并在俄国外交部任职。
1742年,哥德巴赫在教学中发现,每个不小于6的偶数都是两个素数(只能被1和它本身整除的数)之和。如6=3+3,14=3+11等等。公元1742年6月7日哥德巴赫写信给当时的大数学家欧拉,欧拉在6月30日给他的回信中说,他相信这个猜想是正确的,但他不能证明。叙述如此简单的问题,连欧拉这样首屈一指的数学家都不能证明,这个猜想便引起了许多数学家的注意。从哥德巴赫提出这个猜想至今,许多数学家都不断努力想攻克它,但都没有成功。
我们不需要你去证明哥德巴赫猜想。
如果哥德巴赫猜想是正确的,一个(不小于6的)偶数,都是两个素数之和。那么这个偶数能被至少一个素数对表示,如14,即可以表示为14=3+11,也可以表示为14=7+7。不同的偶数对应的素数对的数目是不一样的,如偶数6,就只能表示为6=3+3。对于每个给定的偶数,我们希望知道有多少素数对的和等于该偶数。

Input

有多组测试数据。每组测试数据占一行,包含唯一的一个正偶数n.(6 <= n <= 2^24,)。 输出以EOF结束。

Output

对于每个输入的偶数,输出一行包含唯一的一个整数:表示有多少个素数对的和是输入的偶数。

Sample Input

6
14

Sample Output

1
2

Source

2009湘潭邀请赛

 

题解:

本题n最大可以达到2^24,我们就考虑用一种方法,把所有小于2^24的素数都找出来;

显然枚举1到2^24每个数,直接用sqrt(n)的复杂度来检测是否为素数的方法是不太可行的;

因此使用筛法来求所有小于等于N的素数:

①埃筛(埃拉托斯特尼筛法)

  朴素的思想:素数的倍数必然不为素数。

  实现方法:先假设在1~N的范围内所有的数为素数,例如使用标记数组isPrime[N],就全部先标记为1;然后isPrime[0]=isPrime[1]=0;

       然后i = 2 to sqrt(N)枚举每个数,如果isPrime[i],则枚举j = 2i , 3i , 4i , …… , ki ( ki <= N 且 (k+1)i > N ),全部isPrime[j]=0;

  反证法:假设存在一个数n,它是一个合数,但是isPrime[n]=1,则按照算法,n不存在一个因数满足小于等于sqrt(n)(要是有,n就被筛钓了);

      因此,n必然有一个因数m,满足sqrt(n) < m < n,则必然存在另一个数 M 满足 M * m = n,则M必然小于sqrt(n),这与前面相矛盾,故n必然是素数;

用这样的筛法,我们就可以写出本题的AC代码:

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cmath>
 4 #define MAX 16777220
 5 bool isPrime[MAX];
 6 int n;
 7 void screen()//埃筛求素数
 8 {
 9     memset(isPrime,1,sizeof(isPrime));
10     isPrime[0]=isPrime[1]=0;
11     int sqrt_MAX=(int)ceil(sqrt(MAX));
12     for(int i=2;i<=sqrt_MAX;i++)
13     {
14         if(isPrime[i]) for(int j=i*2;j<=MAX;j+=i) isPrime[j]=0;
15     }
16 }
17 int main()
18 {
19     screen();
20     while(scanf("%d",&n)!=EOF)
21     {
22         int cnt=0;
23         for(int i=1;i<=n/2;i++)
24         {
25             if(isPrime[i] && isPrime[n-i]) cnt++;
26         }
27         printf("%d\n",cnt);
28     }
29 }

 

②欧拉筛法(线性筛法):

  埃筛存在一个缺陷:重复划去某些合数,例如6,既是2的倍数,又是3的倍数,那么它就会被重复划去;

  因此采用一种更加优化的方法筛出素数;

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<cmath>
 4 #define MAX 16777220
 5 int n;
 6 bool isPrime[MAX];
 7 int PrimeNum[MAX/5],cnt=0;
 8 void screen()//欧拉筛法求素数
 9 {
10     memset(isPrime,1,sizeof(isPrime));
11     isPrime[0]=isPrime[1]=0;
12     for(int i=2;i<=MAX;i++)
13     {
14         if(isPrime[i]) PrimeNum[cnt++]=i;
15         for(int j=0;j<cnt;j++)
16         {
17             if(i*PrimeNum[j]>MAX) break;
18             isPrime[(i*PrimeNum[j])]=0;
19             if(i%PrimeNum[j]==0) break;
20                 //比i*PrimeNum[j]更大的数,会被PrimeNum[0]~PrimeNum[j]的素数筛掉
21         }
22     }
23 }
24 int main()
25 {
26     screen();
27     while(scanf("%d",&n)!=EOF)
28     {
29         int cnt=0;
30         for(int i=1;i<=n/2;i++)
31         {
32             if(isPrime[i] && isPrime[n-i]) cnt++;
33         }
34         printf("%d\n",cnt);
35     }
36 }

 

NEFU 2 - 猜想 - [筛法求素数]

标签:秘书   can   cstring   ==   直接   朴素   input   c代码   使用   

原文地址:http://www.cnblogs.com/dilthey/p/7571967.html

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