题目:
• 题意:
给出一个正整数,求出它有多少种方法可以表示成连续的素数的和。例如53 = 5 + 7 + 11 + 13 + 17 = 53,共有两种方法。
• 限制:数字大小2<=n<=10000
• 解法:
第一步,显然先把1~10000的所有素数找出来
第二步,就通过枚举连续素数的起点,来看是否有一段以它为开头的连续素数和为输入的数
• 第一步可以用一种素数筛法,有个结论是1~n范围内的素数个数大概为O(n/logn)
• 那么接下来的枚举完连续素数的开头,即使是在暴力枚举连续素数的结尾,总的复杂度也就O((n/logn)^2),还算可以接受
代码:
// Problem#: 1259
// Submission#: 5124786
// The source code is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
// URI: http://creativecommons.org/licenses/by-nc-sa/3.0/
// All Copyright reserved by Informatic Lab of Sun Yat-sen University
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
#define maxn 10001
bool isPrime[maxn];
int prime[maxn],primeNum;
void getPrime() //快速素数筛法
{
primeNum=0;
memset(isPrime,true,sizeof(isPrime));
for(int i=2;i<=maxn;i++)
{
if(isPrime[i])
prime[primeNum++]=i;
else continue;
for(int j=i*i;j<=maxn;j+=i)
{
isPrime[j]=false;
}
}
}
int getAnswer(int num)
{
int ans=0;
for(int i=0;i<primeNum;i++)
{
for(int j=i,sum=0; j<primeNum && prime[j]<=num; j++)
{
sum+=prime[j];
if(sum==num)
{
ans++;
break;
}
}
}
return ans;
}
int main()
{
getPrime();
int a;
while(scanf("%d",&a)&&a)
printf("%d\n",getAnswer(a));
}
• 当然,同样可以通过前缀和,用二分的方法找到这个连续的素数和可能的结尾,这样做的复杂度是O(n/logn * (log(n/logn)))
代码:
// Problem#: 1259
// Submission#: 5152221
// The source code is licensed under Creative Commons Attribution-NonCommercial-ShareAlike 3.0 Unported License
// URI: http://creativecommons.org/licenses/by-nc-sa/3.0/
// All Copyright reserved by Informatic Lab of Sun Yat-sen University
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
using namespace std;
#define maxn 10001
bool isPrime[maxn];
int prime[maxn], primeNum;
long long sum[maxn];
void getPrime() //快速素数筛法
{
primeNum = 0;
memset(isPrime, true, sizeof(isPrime));
for (int i = 2; i <= maxn; i++)
{
if (isPrime[i])
prime[primeNum++] = i;
else continue;
for (int j = i*i; j <= maxn; j += i)
{
isPrime[j] = false;
}
}
sum[0] = prime[0];//得到前缀和数组
for (int i = 1; i < primeNum; i++)
{
sum[i] = sum[i - 1] + prime[i];
}
}
int getAnswer(int num)
{
int ans = 0;
for (int i = 0; i<primeNum; i++)
{
long long target = (i>0 ? num + sum[i - 1] : num);
int j = lower_bound(sum, sum + primeNum, target) - sum;
int diff = sum[j] - (i>0 ? sum[i - 1] : 0);
if (j < primeNum && diff == num){
ans++;
}
// if(j<primeNum)
// {
// if(i==0)
// {
// while(1){//刚开始一直WA,觉得奇怪,后来发现可能是i=0时还计算sum[i-1](虽然按照理论来说这种情况应该报runtime error的
// 但是还是想试下(sicily貌似这里有bug)
//于是就写了这个无限循环,当i=0可能计算sum[i-1]时会触发
//结果果然Time limit exceed了
//于是就有了
// int diff = sum[j] - (i>0 ? sum[i - 1] : 0);
//这条语句的诞生
// }
// }
// }
}
return ans;
}
int main()
{
getPrime();
int a;
while (scanf("%d", &a) && a)
printf("%d\n", getAnswer(a));
}