NEFU 2 - 猜想 - [筛法求素数]
Posted tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了NEFU 2 - 猜想 - [筛法求素数]相关的知识,希望对你有一定的参考价值。
题目链接: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 - 猜想 - [筛法求素数]的主要内容,如果未能解决你的问题,请参考以下文章