记录17
#include <bits/stdc++.h>
using namespace std;
int main(){
int a[1010]={};
int n,k,cnt=0;
cin>>n>>k;
for(int i=2;i<=n;i++) a[i]=1;
for(int i=2;i<=n;i++){
if(cnt==k) break;
if(a[i]==1){
a[i]==0;
int p=i;
cnt++;
if(cnt==k){cout<<i;break;}
int m=2;
for(int j=p*m;j<=n;j=p*(++m)){
if(a[j]==1){
a[j]=0;
cnt++;if(cnt==k){cout<<j;break;}
}
}
}
}
return 0;
}
突破点
埃拉托色尼筛法是一种著名的素数筛法,可以查找所有直至 n 的素数
关于埃氏筛法的介绍,放到补充部分来讲
思路
写下 2 到 n 之间的所有整数(包括 2 和 n)。
找到尚未删除的最小数,并将其命名为 p; 则 p 是素数。
划掉 p 及其所有尚未划掉的倍数。
如果尚有数未被划掉,请转到步骤 2。
步骤很详细,直接采用模拟做法,就算不知道埃氏筛法,按照上面的四个步骤开始模拟,也能AC
代码简析
int a[1010]={};
a数组来模拟2到n个数
对于 100% 的数据,有 2≤k<n≤1000。👆👆👆👆👆👆
由上面的数据,a数组开到1010
int n,k,cnt=0;
cnt用来记录每次删除的数字
for(int i=2;i<=n;i++) a[i]=1;
模拟输入了2到n个数,a数组的下标代表具体的数,数组里面放1代表数存在,数组为0代表数删除
写下 2 到 n 之间的所有整数(包括 2 和 n)👆👆👆👆👆👆
for(int i=2;i<=n;i++){
...
if(a[i]==1){
...
...
...
}
}
开始一个一个数的找
找到尚未删除的最小数👆👆👆👆👆👆
for(int i=2;i<=n;i++){
...
if(a[i]==1){
a[i]==0;
int p=i;
cnt++;
if(cnt==k){cout<<i;break;}
...
}
}
找到数的第一件事情,就是删除它,即a[i]==0;(a数组存1代表数i存在,存0代表数i不存在)
删除数的同时cnt开始计数,符合删除的个数就跳出
找到尚未删除的最小数,并将其命名为 p; 则 p 是素数。👆👆👆👆👆👆
for(int i=2;i<=n;i++){
...
if(a[i]==1){
a[i]==0;
int p=i;
cnt++;
if(cnt==k){cout<<i;break;}
int m=2;
for(int j=p*m;j<=n;j=p*(++m)){
if(a[j]==1){
a[j]=0;
cnt++;if(cnt==k){cout<<j;break;}
}
}
}
}
开始删除筛选出来的数,m的作用是一点点地找到i的倍数j
每找一个数,cnt++就开始计数,找到后输出这个倍数
划掉 p 及其所有尚未划掉的倍数。👆👆👆👆👆👆
for(int i=2;i<=n;i++){
if(cnt==k) break;//如果上一轮在倍数中找到了,直接跳出循环
if(a[i]==1){
a[i]==0;
int p=i;
cnt++;
if(cnt==k){cout<<i;break;}
int m=2;
for(int j=p*m;j<=n;j=p*(++m)){
if(a[j]==1){
a[j]=0;
cnt++;if(cnt==k){cout<<j;break;}
}
}
}
}
如果上一轮在倍数中找到了,直接跳出循环
如果尚有数未被划掉,请转到步骤 2。👆👆👆👆👆👆
补充
埃拉托斯特尼筛法(Sieve of Eratosthenes),简称埃氏筛法,是一种用于找出一定范围内所有素数的古老算法。它通过逐步筛选掉合数,最终留下素数。这种方法非常直观且高效,特别适合在竞赛编程中使用。
埃氏筛法的基本思想
初始化:创建一个布尔数组
is_prime,大小为n+1,并将所有元素初始化为true。数组的索引表示数字,is_prime[i]表示数字i是否为素数。标记非素数:从2开始,逐步标记所有素数的倍数为非素数。
输出结果:遍历数组,所有值为
true的索引即为素数。详细步骤
初始化数组:
创建一个布尔数组
is_prime,大小为n+1,并将所有元素初始化为true。特殊处理:
is_prime[0]和is_prime[1]设置为false,因为0和1不是素数。筛选非素数:
从2开始,逐步遍历数组。
如果
is_prime[i]为true,则i是一个素数。将
i的所有倍数标记为false,因为这些数不是素数。输出结果:
遍历数组,所有值为
true的索引即为素数。示例代码
以下是一个实现埃氏筛法的C++代码:
#include <iostream> #include <vector> using namespace std; vector<int> sieveOfEratosthenes(int n) { vector<bool> is_prime(n + 1, true); // 初始化布尔数组 is_prime[0] = is_prime[1] = false; // 0和1不是素数 for (int i = 2; i * i <= n; i++) { if (is_prime[i]) { for (int j = i * i; j <= n; j += i) { is_prime[j] = false; // 标记i的倍数为非素数 } } } vector<int> primes; for (int i = 2; i <= n; i++) { if (is_prime[i]) { primes.push_back(i); // 收集所有素数 } } return primes; } int main() { int n; cout << "Enter the upper limit: "; cin >> n; vector<int> primes = sieveOfEratosthenes(n); cout << "Prime numbers up to " << n << " are:" << endl; for (int prime : primes) { cout << prime << " "; } cout << endl; return 0; }示例输入和输出
输入:
Enter the upper limit: 30输出:
Prime numbers up to 30 are: 2 3 5 7 11 13 17 19 23 29详细解释
初始化数组:
创建一个布尔数组
is_prime,大小为n+1,并将所有元素初始化为true。特殊处理:
is_prime[0]和is_prime[1]设置为false,因为0和1不是素数。筛选非素数:
从2开始,逐步遍历数组。
如果
is_prime[i]为true,则i是一个素数。将
i的所有倍数标记为false,因为这些数不是素数。注意,从i * i开始标记即可,因为小于i * i的倍数已经在之前的步骤中被标记过了。输出结果:
遍历数组,所有值为
true的索引即为素数。为什么从
i * i开始标记
如果
i是一个素数,那么i的所有小于i * i的倍数(如2i,3i,4i, ...)在之前的步骤中已经被标记过了。例如,当
i = 2时,2 * 2 = 4,2 * 3 = 6,2 * 4 = 8等已经在之前的步骤中被标记为非素数。因此,从
i * i开始标记即可,这样可以减少不必要的计算。时间复杂度
埃氏筛法的时间复杂度是 O(nloglogn),这使得它在处理较大范围的素数时非常高效。
总结
埃氏筛法是一种简单且高效的算法,用于找出一定范围内的所有素数。通过逐步筛选掉合数,最终留下素数。
620

被折叠的 条评论
为什么被折叠?



