2018年蓝桥杯省赛 1.第几个幸运数字 知识点:找规律

59 阅读2分钟

题目:1.第几个幸运数字 - 蓝桥云课 (lanqiao.cn)

解析:201804第几个幸运数_哔哩哔哩_bilibili

暴力思想

刚开始想法是这样的:

如果可以整除3,5,7中的任何一个,那么就统计一下:

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const LL Max=3579152125273545; 
int main()
{
	int ans=0;
	
	for(int i=3;i<=Max;i++)
	{
		int x=i;
			while(x%3==0)x=3;
			while(x%5==0)x/=5;
			while(x%7==0)x/=7;
			if(x==1)ans++;
	}

  cout<<ans;
	return 0;
} 

但是肯定是跑不出结果的:

image.png

原因是它给的数据是16位:

image.png

也就是说要跑16个小时才能跑出来。

这个时候需要我们换种想法,假设我们联想到素数的求法,素数的求法有两种,一种是试除法,一种是筛法。

试除法因为是挨个枚举所以时间复杂度为O(n),遇上n比较大的时候就跑不过去。

而筛法利用了某些特性可以提高效率,降低时间复杂度:

image.png

另一种思想

这道题我们也要利用特性来做:

首先刚开始是:

3 5 7

刚开始头部是3,由3乘每一位数,得到一个全新的数列:

3 5 7 9 15 21

此时3已经用完了,头部换位5,由5乘数列里的所有成员,5乘3=15,我们发现重复了,应该去掉。 5 7得到一些值插入到后面:

3 5 7 9 15 21 35

最后再用7乘7=49,也插入到2尾部:

3 5 7 9 15 21 35 49

此时3 5 7已经用完了,我们需要寻找新的头部继续重复新的操作:

9*3 9*5 9*7 9*15……

总结:序列的值都是由3 5 7相乘得到的,刚开始头部是3,当3用完之后我们就需要换一个头部。

换头的规则是:比前一个头刚好大的那个数,换句话说是比前面的数大的最小数。

我们发现在相乘的过程中会遇到乘积重复的问题,因此我们还需要考虑去重的问题。我们可以用set来去重。

#include<iostream>
#include<set>
using namespace std;
typedef long long LL;
const LL Max=59084709587505; 
int main()
{
     int  a[3]={3,5,7};
	set<LL>s;
	LL tou=1;
	while(true)
	{
		for(int i=0;i<3;i++)
		{
			LL tt=tou*a[i];              //头部乘所有的成员 
			if(tt<=Max)s.insert(tt);    //只要比59084709587505就一直往set里扔 
		}
		
		tou=*(s.upper_bound(tou));  //比头大的最小的数的那个指针,再解引用得到那个数
		if(tou>=Max)break;         //肯定有个数刚好是59084709587505,这个时候就退出 
	}
	cout<<s.size();
	return 0;
} 

image.png