您的位置:首页 > 编程语言 > C语言/C++

2017第八届蓝桥杯C++B组省赛之等差素数列题

2018-03-31 18:48 399 查看
题目的要求如下:
2,3,5,7,11,13,....是素数序列。类似:7,37,67,97,127,157 这样完全由素数组成的等差数列,叫等差素数数列。上边的数列公差为30,
长度为6。2004年,格林与华人陶哲轩合作证明了:存在任意长度的素数等差数列。这是数论领域一项惊人的成果!

有这一理论为基础,请你借助手中的计算机,满怀信心地搜索:长度为10的等差素数列,其公差最小值是多少?
注意:需要提交的是一个整数,不要填写任何多余的内容和说明文字。

    看完题目的要求,想必大家肯定知道了这道题目要把一个很大范围的数列中筛选出素数来,那么在筛选素数的方法中,有一种叫做埃拉托斯特尼筛法的方法,下面是对其简介:

埃拉托斯特尼筛法

埃拉托斯特尼筛法(希腊语:κόσκινον Ἐρατοσθένους,英语:sieve of Eratosthenes ),简称埃氏筛,也有人称素数筛。这是一种简单且历史悠久的筛法,用来找出一定范围内所有的素数
所使用的原理是从2开始,将每个素数的各个倍数,标记成合数。一个素数的各个倍数,是一个差为此素数本身的等差数列。此为这个筛法和试除法不同的关键之处,后者是以素数来测试每个待测数能否被整除。

算式 pogczman resident sleeper

给出要筛数值的范围n,找出{\displaystyle {\sqrt {n}}}

以内的素数{\displaystyle p_{1},p_{2},\dots ,p_{k}}

。先用2去筛,即把2留下,把2的倍数剔除掉;再用下一个素数,也就是3筛,把3留下,把3的倍数剔除掉;接下去用下一个素数5筛,把5留下,把5的倍数剔除掉;不断重复下去......。

步骤[编辑]



详细列出算法如下:列出2以后的所有序列:2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

标出序列中的第一个质数,也就是2,序列变成:2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25

将剩下序列中,划摽2的倍数(用红色标出),序列变成:2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 2223 24 25

如果现在这个序列中最大数小于最后一个标出的素数的平方,那么剩下的序列中所有的数都是质数,否则回到第二步算式 。


C++

const long long N=1000010;
//dp[x]=0表示x为质素 
int dp
={1,1,0};
//prim用来存储筛选出来的质素,total为素数的个数 
int prim
={0};
int total=0;
void init(){
for(long long i=2;i<N;i++){
if(dp[i]==1)continue;//i如果为1,则不为质素,直接跳过
if(dp[i]==0){//此时的i为质素 
prim[total++]=i;//prime数组专门记录筛选出来的质素 
for(long long j=i;j*i<N;j++){
dp[j*i]=1;//i的所有倍数全部为非质素,标记为1 
}
}
 
}
}
    上面为求0到1000010范围之内的素数,用dp数组容纳,然后对dp数组中的所有数字进行素数筛选操作,即符合素数的倍数一定不是素数的准则,dp[x]的值为0或者1,dp[x]=0则表示数字x为素数,相反为1则表示不为素数。而prime数组则用来存储从dp数组中筛选出来的素数,total不仅记录了一共筛选出了多少个素数(prime数组中的数据量),并且也指向了下一个素数应该存放在prim数组中的索引。
    这里重点解释一下for(long long j=i;j*i<N;j++){这一句当中的j*i<N,开始我们说了,如果数字x为素数,则2x,3x,4x......一定不可能也为素数的,所以我们可以把2x,3x,4x......全部给标记为非素数,之所以使用j*i<N做判定条件,而不是使用从2开始,乘以每一个x,在用3乘以每一个x,这样虽然也可以,但是效率不高,例如2是素数时,进行筛选操作时,则2*2=4,2*3=6,2*4=8,....,4,6,8就已经被标记为非素数,而当i为3时,进行筛选操作时,如果也按照从2开始,则有3*2=6,3*3=9,3*4=12.....,6,9,12被标记为非素数,此时我们发现数字6被重复标记了,我们只需要从3*3开始筛选就好了,所以当筛选i时,直接从i*i开始筛选就好了。因为i*(i-1)这一步骤在筛选i-1时就已经执行了(i-1)*i这一步骤了,这两个步骤是相同的。

此时,我们筛选出了素数后,可以通过dp数组来判断一个数是否为素数,而通过prim来获取所有筛选出来的素数,通过这两个数组,在用暴力破解法去试每一个素数和每一个公差就好了,下面是具体的代码:
int main(){
init();

//此时prime【】数组中为筛选出来的素数,只要对其进行每一个元素都进行判断即可
for(int d=1;d*10<N;d++){//d为公差,从1开始慢慢增加
for(int i=0;i<total;i++){//遍历prime中的每一个质素并对其进行10个等差数的判断
int flag=1;//假设遍历的该质素刚好符合条件,flag为1 
int temp=prim[i];
for(int k=1;k<10;k++){//每个质素只需要加9次公差进行判断即可 
if(temp+d>=N||dp[temp+d]==1){
flag=0;
break;

else{
temp+=d;
}
}

if(flag==1){
cout<<d<<endl;
return 0;






    return 0;
}


最后的答案是210.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: