题目:1.第几个幸运数字 - 蓝桥云课 (lanqiao.cn)
暴力思想
刚开始想法是这样的:
如果可以整除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;
}
但是肯定是跑不出结果的:
原因是它给的数据是16位:
也就是说要跑16个小时才能跑出来。
这个时候需要我们换种想法,假设我们联想到素数的求法,素数的求法有两种,一种是试除法,一种是筛法。
试除法因为是挨个枚举所以时间复杂度为O(n),遇上n比较大的时候就跑不过去。
而筛法利用了某些特性可以提高效率,降低时间复杂度:
另一种思想
这道题我们也要利用特性来做:
首先刚开始是:
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;
}