题目描述
小李在你帮助之下轻松战胜了他的同学们,于是满怀恶意的同学出了一个题目来为难小李,作为小李神一样的队友,你又要出力了。
素数41能写成连续6个素数之和:41=2+3+5+7+11+13。
现在要求n以内的素数中,能表示为最多连续素数之和的那个数,如果有多个答案,请输出最大的那个素数。
输入
仅一行,一个整数n(1<=n<=1000000)。
输出
输出就一个整数,为所求的能表示为最多连续素数和的那个素数。
分析:
1.首先不要理解错题意,我就理解错了,我以为都是从2开始加,后来发现可能后面的加起来的等于的数要大而且要多。
2.根据这个题目来言,首先要进行素数打表,不然之后挨个判断是否为素数过于麻烦。
3.题目要求输出最大的那个素数。
思路:
我们可以先从2开始把之后的素数都加一遍,直到他大于n就结束,在这之前保留最大的那个素数。然后在从3开始,直到和大于n结束,这样以此枚举。然而问题是,怎么找到素数最多的那个而且又是最大的数,我们可以用区间长度,来表示,例如从2开始加到 这就 3-2+1=2,所以这中间有两个素数,如果以后枚举过程中,遇到区间长度一样的,应该输出后来的数,因为要输出最大的素数(肯定越往后加,和越大),具体实现代码如下:
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <stdlib.h>
#include <math.h>
using namespace std;
int vis[(int)(1e6+5)];
int prime[(int)(1e6+5)];
int main(){
int cnt=0;
for(int i=2;i<=1e6;i++)
if(!vis[i])
{
prime[++cnt]=i;
for(int k=2*i;k<=1e6;k+=i)
vis[k]=1;
}
int sum=0;
int num=0;
int m,n,x;
scanf("%d",&n);
for(int i=1;i<=cnt&&prime[i]<=n;i++)
{
sum=0;
for(int k=i;k<=cnt;k++)
{
sum+=prime[k];
if(sum<=n&&!vis[sum])
{
num1=k-i+1;//k-i+1表示区间长度
x=sum;
}
if(sum>n)
break;
}
if(num1>=num)//每次找到符合要求的数比较一下区间长度,也就是之前的素数个数
{
m=x;//最大值更新
num=num1;//区间长度更新
}
}
printf("%d",m);
return 0;
}
附加一个简略代码:
#include <stdio.h>
#include <algorithm>
#include <string.h>
#include <stdlib.h>
#include <math.h>
using namespace std;
int vis[(int)(1e6+5)];
int prime[(int)(1e6+5)],num[500000];
int main(){
int cnt=0;
for(int i=2;i<=1e6;i++)
if(!vis[i])
{
prime[++cnt]=i;
for(int k=2*i;k<=1e6;k+=i)
vis[k]=1;
}
int n;
scanf("%d",&n);
int num=0,ans=0;//zui chang
for(int x=1;x<=cnt&&prime[x]<=n;x++)
{
int sum=0;
for(int i=x;i<=cnt;i++)
{
sum+=prime[i];
if(!vis[sum]&&sum<=n)
{
if(i-x+1>=num) ans=max(ans,sum),num=i-x+1;
}
if(sum>n) break;
}
}
printf("%d\n",ans);
return 0;
}
思想是一样的,更为简单而已。
简单代码,有错指正。