POJ 2739 Sum of Consecutive Prime Numbers(素数表的应用)

原题地址

http://poj.org/problem?id=2739

题意:某些数字可以由连续几个素数的和表示,给定一个数字,求其有几种这样的表示方法。例:41=2+3+5+7+11+13 或 41=11+13+17

解题思路

素数表

既然要判断某个数能否表示为连续的素数和,那么首先就要知道如何求素数。
素数是数论和离散数学里非常重要的一部分,这里就如何用“筛法”得到n之内的素数表作总结(参考了以前做EOJ1006时存过的一个word文档)。

求[2,n]之间所有素数的素数筛法步骤如下:

  1. 申请大小为n+1大小的bool型数组visit[],用于遍历的同时确定素数,可以先全部初始化为true。
  2. 除2以外所有的偶数都不是素数,因此所有大于2的偶数的标为false,所有奇数的仍为true。
  3. 遍历所有奇数i。当i是素数时,i的所有倍数(大于等于2倍)必然是合数,将这些合数标为false,如果i已经不是素数,找i后一个素数做倍数筛法。
  4. 所有visit值为true的下标i即所求区间内的素数,存入目标表prime中。

这种筛法相比直接从i遍历到n筛去i的倍数,消耗时间可以大幅下降。

需要注意的几个点:

  • 第2步的for循环的末尾循环体可以用 i+=2,第3步中的对i的成倍增加也可以用 j+=i
  • 第3步中做遍历时,只需要对[2,sqrt(n)]间的数做筛法,因为若数字X存在1和其本身以外的因子,那么这对因子一定有一个数小于等于sqrt(n),容易反证得出结论。

枚举可能的连续素数和

这一步思想很简单,两层循环就够了:
先确定第一个素数,再从该素数的下一个素数开始依次累加,直到刚好累加到n则表达方法加一(或累加到大于n跳出),更换首个素数,重复这些步骤。

AC代码如下

#include <iostream>
#include <cstring>
#include <cmath>
#define MAXN 10005
using namespace std;

bool visit[MAXN];
int prime[MAXN] = {0};
int cnt = 0;

void BuildTable(int N) //素数筛法+打表
{
    memset(visit, true, sizeof(visit));
    for (int i = 4; i<=N; i += 2) //筛掉偶数,除2以外的偶数都不是素数
        visit[i] = false;
    for (int i = 3; i <= sqrt(N); i += 2) //检查所有奇数,如果x不是质数,那么它的某个因子一定不大于sqrt(x)
    {
        if (visit[i]) //i是素数(不存在比它小的因子)
        {
            int j = i<<1; //倍数至少是2,跳过i+1~2i
            while(j < N) //筛掉从2i~N间i的倍数
            {
                if (j%i == 0) visit[j] = false;
                j += i; //j成倍增加
            }
        }
    }
    for (int i = 2; i < N; ++i) //记录2~N间所有素数
        if (visit[i]) prime[cnt++] = i;
}

int main()
{
    BuildTable(10000);
    int n;
    while(cin >> n)
    {
        if (n == 0) break;
        int ways = 0, Index1, Index2;
        for (Index1 = 0; Index1 < cnt && prime[Index1] <= n; ++Index1) //连续素数和的第一个素数
        {
            int addup = prime[Index1];
            for (Index2 = Index1+1; Index2 < cnt && addup <= n; ++Index2) //连续素数和的后续素数
            {
                if (addup < n)
                    addup += prime[Index2];
                else if (addup == n) //累加到n,第一个素数后移
                {
                    ways++;
                    break;
                }
            }
        }
        cout << ways << endl;
    }
    return 0;
}

内存占用:740K 耗时:0ms
算法复杂度:O(n^2)

相关题目

POJ 2262 Goldbach’s Conjecture
http://poj.org/problem?id=2262
POJ 2739 Sum of Consecutive Prime Numbers
http://poj.org/problem?id=2739
POJ 3006 Dirichlet’s Theorem on Arithmetic Progressions
http://poj.org/problem?id=3006

posted @ 2017-03-28 21:48  Lecholin  阅读(116)  评论(0编辑  收藏  举报