题解 - 连续质数和

题目描述

质数又称素数,是大于 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值