洛谷 P5723 【深基4.例13】质数口袋 题解
题目描述
小 A 有一个质数口袋,里面可以装各个质数。他从 2 2 2 开始,依次判断各个自然数是不是质数,如果是质数就会把这个数字装入口袋。
口袋的负载量就是口袋里的所有数字之和。
但是口袋的承重量有限,装的质数的和不能超过 L L L。给出 L L L,请问口袋里能装下几个质数?将这些质数从小往大输出,然后输出最多能装下的质数的个数,数字之间用换行隔开。
输入格式
一行一个正整数 L L L。
输出格式
将这些质数从小往大输出,然后输出最多能装下的质数个数,所有数字之间有一空行。
样例 #1
样例输入 #1
100
样例输出 #1
2
3
5
7
11
13
17
19
23
9
样例 #2
样例输入 #2
5
样例输出 #2
2
3
2
样例 #3
样例输入 #3
11
样例输出 #3
2
3
5
3
提示
数据保证, 1 ≤ L ≤ 10 5 1 \le L \le {10}^5 1≤L≤105。
思路
埃氏筛法
根据通过质数去把所有合数都删掉的思路,可以优化方一的普通筛法。
(因为合数都可以以质数的乘积形式获得)
时间复杂度分析:O(nloglogn)
1~n中有n/lnn个质数,
要比原来的nlnn少算lnn倍,粗略估计有O(n)
但真实的时间复杂度是O(nloglogn) 很小 几乎接近O(n)
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 5; // 定义数组大小
int prime[N]; // 用于存储素数的数组
bool vis[N]; // 标记非素数的布尔数组
// 埃拉托色尼筛法函数,用于标记素数
int seive(int l) {
int n = 0; // 记录素数的数量
fill(vis, vis + l + 1, false); // 初始化标记数组
for (int i = 2; i <= l; i++) { // 从2开始遍历到l
if (!vis[i]) { // 如果i未被标记为非素数
prime[n++] = i; // 将i存入素数数组
for (int j = i * 2; j <= l; j += i) { // 标记i的所有倍数为非素数
vis[j] = true;
}
}
}
return n; // 返回找到的素数数量
}
int main() {
int l;
cin >> l; // 输入上限值l
int num = seive(l); // 调用筛法函数,返回素数数量
int sum = 0, n = 0; // 初始化素数和及计数器
for (int i = 0; i < num; i++) {
if (sum + prime[i] > l) break; // 如果当前和超过l,则退出循环
cout << prime[i] << endl; // 输出当前素数
sum += prime[i]; // 累加当前素数到和
n++; // 素数计数器加1
}
cout << n << endl; // 输出素数个数
return 0;
}