题目描述
质数又称素数,是大于 1 的正整数,除了 1 和它本身外不能被其他自然数整除,有无限 个,比如,2、3、5、7 等都是质数,但比如 9 就不是质数,因为它除了能被 1 和它自己整 除外,还能被 3 整除。
悦悦小朋友对这类质数非常感兴趣,因为他发现有一些数是能通过连续的质数相加得 到的。比如 5+ 7 + 11 + 13 + 17=53,也就是整数 53 可以由连续的质数 5、7、11、13、17 相 加得到。有时相加的方案还不止一种,比如整数 41 就有 3 种不同的连续质数相加方案:
2+3+5+7+11+13=41,11+13+17=41,还有一种就它本身,即 41=41。但也有的数是没有这样
相加方案的,比如整数 20 就找不到连续质数相加的方案,虽然 7 + 13 或者 3 + 5 + 5 + 7 的 结果都是 20,但前者没有连续,后者质数被重复相加了 。悦悦在纸上写了 N(1≤N≤100000) 个数,他想知道每一个整数 Mi(2≤Mi≤100000,1≤i≤N)到底有多少种连续质数相加的 方案?请你编程帮助他一下吧。
输入
输入共 N+1 行。 第 1 行一个整数 N,表示悦悦在纸上写了 N 个整数。
接下来每行一个整数,其中第 i+1 行表示整数 Mi
输出
输出共 N 行。 输出的第 i 行表示整数 Mi 有多少种连续质数相加的方案。
样例输入 Copy
4
2
12
17
20
样例输出 Copy
1
1
2
0
提示
样例中悦悦写了4个整数,分别为2,12,17和20。因为2=2,所以2可以找到满足条件的1种方案。
因为5+7=12,所以12有1种方案。
因为2+3+5+7=17,17=17,所以17有2种方案满足条件。
20没有满足条件的方案,所以输出0。
对于30%的数据保证1≤N≤100,2≤Mi≤100。对于50%的数据保证1≤N≤1000,2≤Mi≤1000。
对于100%的数据保证1≤N≤100000,2≤Mi≤100000。
题意
给出n个数,求每个数可以有多少种连续质数相加的方案
分析
本题 n <= 100000,故需要先进行预处理
先用素数筛筛出100000以内的素数,再求前缀和,统计连续质数和对应的数的个数,然后再进行n次询问即可
由于本题n只有1e5,又因为需要用到前缀和,所以选择O(nloglogn)的埃氏筛来筛素数
因为线性筛得到的数组下标从0开始,若进行前缀和还需要单独的分类讨论,比较麻烦
再进行一下优化,如果当前区间内的连续质数和大于a[i]的最大值,直接结束当前循环即可
代码
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 100000 + 10;
int n;
int a[N];
int primes[N], cnt;
bool st[N];
LL s[N];
int sum[N];
int mx;
void get_primes(int x){
for (int i = 2; i <= x; i ++ ){
if (st[i]) continue;
primes[++cnt] = i;
s[cnt] = s[cnt - 1] + primes[cnt]; // 前缀和
for (int j = i + i; j <= x; j += i)
st[j] = true;
}
}
int main(){
ios::sync_with_stdio;
cin.tie(0),cout.tie(0);
cin >> n;
for(int i = 0;i < n;i++){
cin >> a[i];
mx = max(mx,a[i]); // 求a[i]的最大值
}
get_primes(mx); // 筛素数
for(int i = 1;i <= cnt;i++)
for(int j = 1;i + j - 1 <= cnt;j++){
LL tmp = s[i + j - 1] - s[i - 1];
if(tmp <= mx) sum[tmp]++;
else break; // 优化
}
for(int i = 0;i < n;i++) cout << sum[a[i]] << '\n';
return 0;
}