整数分解与筛法 Sum of Consecutive prime Numbers

题目 A: 连续质数之和

有些正整数可以表示成一个或多个连续质数的和。你能算出给定的正整数有多少种这样的表示方法吗?比如,数字 53 有两种表示方法:5 + 7 + 11 + 13 + 17 和 53 本身。数字 41 有三种表示方法:2 + 3 + 5 + 7 + 11 + 13,11 + 13 + 17,以及 41。数字 3 只有一种表示方法,就是 3。数字 20 没有任何这样的表示方法。注意,组成和的质数必须是连续的,所以像 7 + 13 或 3 + 5 + 5 + 7 这样的组合都不算有效表示。

你的任务是写一个程序,输出给定正整数的所有连续质数和的表示数量。

输入格式

输入是一串正整数,每个数字占一行,范围在 2 到 10 000 之间(含)。当输入为 0 时,表示输入结束。

输出格式

对于每个输入的正整数(不包括最后的 0),输出一行,表示该数字可以用连续质数之和表示的方案数。输出中不要添加任何多余字符。

Input复制 Output复制
2 1
3 1
17 2
41 3
20 0
666 0
53 2
0

算法分析

首先看数据范围,输入的数<10000,但有多组数据,所以不能用O(n^2)的做法。接下来考虑因为10000以内的质数并不多,再看到对连续的数求和时,很容易想到前缀和,所以,思路如下:

  1. 预处理求出10000以内的质数。

  2. 对求出的质数求前缀和。

  3. 建一个cnt数组,表示和为i的连续质数有多少种。

  4. 对输入的数求前缀和。

坑点:

  • 输入有多组数据且遇到最后的0时要结束。
  • 由于题目只要求10000以内的数,所以统计方案数时如果遇到一段质数的和大于10000,要直接跳出循环,不然会RE。
#include<bits/stdc++.h>
using namespace std;
int n;
vector<int> v;
bool vis[10005];
long long a[10005];
long long cnt[10005];
void zs(){//预处理求出10000以内的质数并存好
    for(int i = 2; i<=10000; i++){
        if(vis[i]==0){
            v.push_back(i);
            for(int j = i+i; j<=10000; j+=i){
                vis[j] = 1;
            }
        }
    }
}
int main(){
	ios::sync_with_stdio(0);//加速器
	cin.tie(0);
	cout.tie(0);
    zs();
    int len = v.size();
    for(int i = 0; i<len; i++){
    	a[i+1] = a[i]+v[i];//前缀和
	}
	for(int i = 1; i<=len; i++){
		for(int j = i; j<=len; j++){
			if(a[j]-a[i-1]>10000){//判断是否是无效数据,不判断会RE
				break;
			}
			cnt[a[j]-a[i-1]]++;//统计
		}
	}
    while(cin>>n){
        if(n==0){
        	return 0;
		}
		cout<<cnt[n]<<'\n';//输出对应的值
    }
	return 0;
}
posted @ 2026-06-14 11:37  xmgene  阅读(16)  评论(0)    收藏  举报