【蓝桥杯】幸运数

时间:2022-09-09 22:47:44

【蓝桥杯】幸运数



算法思想:类比素数打表, 但是速度很慢

#include<iostream>
#include<cstdio>
using namespace std;

int a[500000 + 1];
int m, n;

void lucky(int start, int len) {
int k = start, num = a[start];
for(int i = k; i < len; i++) {
if(i % num != 0) {
a[k++] = a[i];
}
}
if(num < len && a[start + 1] < n) {
lucky(start + 1, k);
}
}

int main() {
cin >> m >> n;
int len = 500000, kinds = 0;
for(int i = 1; i < len; i++) a[i] = 2 * i - 1;
lucky(2, len);
for(int i = 1; i < len; i++) {
if(a[i] >= n || a[i] == a[i - 1]) {
break;
}
if(a[i] > m && a[i] < n) {
kinds++;
}
}
cout << kinds;
return 0;
}

另一个犇给的代码,我进行了注释,注释可能有措辞不当的地方请自行脑补


#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cstdio>
using namespace std;

const int maxn = 1000010;
bool flag[maxn]; //用于标记是不是幸运数
int m, n; //记录范围的m, n
int a[maxn], s[maxn], size = 0; //数组a存储幸运数i的位置(幸运数列中的)

int fa(int k) { //用于寻找幸运数的个数
if( flag[k] ) {
return a[k];
}
return fa(k - 1);
}

int main() {
cin >> m >> n;
for(int i = 1; i <= n; i += 2) {
s[++size] = i; //数组s存储幸运数列
flag[i] = true; //数组flag表示数字i是不是幸运数
a[i] = size; //a[i]存储了i之前(包括i)的幸运数的个数
}
for(int i = 2; i <= size; i++) {
int mod = s[i], d = s[i] - 1; //mod是原来幸运数序列的第i个数
if(mod > size) {
break;
}
for(int p = 1, j = mod; j <= size; j += mod, p++) { //因为每次删除的都是j到2j的非幸运数,但是没有删除2j到3j的,为此每删除一轮,p自增一次
flag[ s[j] ] = false; //mod的倍数一定不是幸运数,标记删去
for(int k = 1; k < mod && k + j <= size; k++) { //k < mod, 故k + j < 2 * mod
s[++d] = s[j + k]; //更新幸运数序列
a[ s[j + k] ] -= p; //s[j + k]之前的幸运数个数减少p个
}
}
size = d; //更新幸运数序列长度
}
printf("%d", fa(n - 1) - fa(m)); //幸运数个数相减,即是从 m 到 n - 1的幸运数个数
return 0;
}