Sicily 1259. Sum of Consecutive Primes |

题目:
这里写图片描述

• 题意:
给出一个正整数,求出它有多少种方法可以表示成连续的素数的和。例如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));
}                                 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值