问题描述
幸运数是波兰数学家乌拉姆命名的。它采用与生成素数类似的“筛法”生成
。
首先从1开始写出自然数1,2,3,4,5,6,…
1 就是第一个幸运数。
我们从2这个数开始。把所有序号能被2整除的项删除,变为:
1 _ 3 _ 5 _ 7 _ 9 …
把它们缩紧,重新记序,为:
1 3 5 7 9 … 。这时,3为第2个幸运数,然后把所有能被3整除的序号位置的数删去。注意,是序号位置,不是那个数本身能否被3整除!! 删除的应该是5,11, 17, …
此时7为第3个幸运数,然后再删去序号位置能被7整除的(19,39,…)
最后剩下的序列类似:
1, 3, 7, 9, 13, 15, 21, 25, 31, 33, 37, 43, 49, 51, 63, 67, 69, 73, 75, 79, …
输入格式
输入两个正整数m n, 用空格分开 (m < n < 1000*1000)
输出格式
程序输出 位于m和n之间的幸运数的个数(不包含m和n)。
样例输入1
1 20
样例输出1
5
样例输入2
30 69
样例输出2
8
思路
看着数挺大的,但是数据应该挺水的,只用了31ms。
ps:第一个幸运数虽然是1,但是要把2当作幸运数来进行遍历删除
模拟:先开一个数组,1代表幸运数,inf代表被删去,首先要确定当前的幸运数是什么,然后遍历,如果某个位置没有被删除,计数器c就+1,每当计数器c等于幸运数,就可以删除该位置的数组(赋值为inf)
比如样例一:1 - 20 (1为幸运数,把2当作幸运数操作)
开始 : 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
第一次: 1 inf 0 inf 0 inf 0 inf 0 inf 0 inf 0 inf 0 inf 0 inf 0 inf
(下一个幸运数就是第一个为0的数组下标值,为3)
(inf 是被删除的值,后面操作时跳过,比如第二次幸运数为3,那么第一个删除的值应该是数组下标5,因为前面有两个inf,这两个数已经被删除,所以数组下标5就是当前数组的第3个数,以此类推)
.。。。。。。。。。。。。。。。。
就这样一直下去,直到幸运数查找到了最后一个数,退出循环
代码:
#include <iostream>
#include <algorithm>
#include <vector>
#include <queue>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <set>
using namespace std;
const int maxn=1e6+50;
const int inf=1<<27; //表示被删除
int a[maxn]={0}; //1代表幸运数
int ans=0,flag=0; //ans记录个数 , flag判断跳出循环
int main()
{
int n,m;
int p=2; //当前幸运数
cin>>m>>n;
a[1]=1;
while(1)
{
int c=0;
for(int i=1;i<=n;i++)
{
if(a[i]!=inf) //没有被删除
{
c++; //计数器+1
if(c==p) //(计数器等于幸运数)
{
a[i]=inf; //删除
c=0; //计数器归0
}
}
}
for(int i=1;i<=n;i++)
{
if(i==n) flag=1;
//幸运数找到最后一个位置了(后面没了)
//此时标记flag,准备跳出循环
if(a[i]==0)//第一个为0的数
{
a[i]=1; //记为幸运数
p=i; //更新当前幸运数
break; //退出循环
}
}
if(flag==1) break; //跳出循环
}
for(int i=m+1;i<n;i++)
if(a[i]==1) ans++; //记录幸运数的个数
cout<<ans;
return 0;
}