题目描述
题解
此题的数据范围应为
109
.
首先找出[1,r]中所有的baka数,可以计算出只有
21+22+..+29=1023
个。
其次可以发现当存在两个baka数
ab
满足
a|b
的话,那么b是没有价值的,根本不用判断。
所以就把baka数中有因数也是baka数的剔除掉,可以发现只剩下了499个数。
然后可以进行dfs,x,y,lcm分别表示选到第x个数,之前已经选了y个数,所有选的数的lcm。答案=是一个数公倍数的数量-是两个数公倍数的数量+是三个数公倍数的数量…
根据y的奇偶统计答案就行了。
不过这道题非常让我迷惑的一点是时间复杂度。因为这样dfs的话
1010
是跑不出来的。把那449个数打表后可以发现,最小的6个数乘起来已经超过了
109
,也就是说,在最坏情况下,dfs的时间复杂度应该为
O(C6499)≈2∗1013
。但是实际上,只有12个数在
103
级别之内,只有26个数在
104
级别之内,也就是说,大部分情况下,选的数的个数不会大于2.我们先忽略不计前38个数,后面的所有的数的搜索复杂度大约应为
O(C2461)≈105
;不考虑后面的数,前38个数在最坏情况下复杂度约为
O(C638)≈3∗106
;而考虑将前38个数和后面的组合一下的话,很显然后面的数只有可能选一个,前面的数最多选4个,那么
O(C438∗C1461)≈3.5∗107
.那么这样的话,估算的时间复杂度不会超过
108
.而如果是
1010
的范围的话,合法的数的个数达到了969个,用同样的方法计算明显时间是承受不住的。
那么我们就用这样一种不靠谱的方法证明了这道题的时间复杂度!
代码
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
#define LL long long
#define N 10000
LL l,r,a[N],b[N],ans;
bool vis[N];
void get(LL x)
{
if (x>r) return;
if (x) a[++a[0]]=x;
get(x*10+2);
get(x*10+9);
}
LL gcd(LL a,LL b)
{
return (!b)?a:gcd(b,a%b);
}
void dfs(int x,int y,LL lcm)
{
if (x>b[0])
{
if (y&1) ans+=r/lcm-(l-1)/lcm;
else if (y) ans-=r/lcm-(l-1)/lcm;
return;
}
dfs(x+1,y,lcm);
lcm=(lcm*b[x])/gcd(lcm,b[x]);
if (lcm<=r) dfs(x+1,y+1,lcm);
}
int main()
{
scanf("%lld%lld",&l,&r);
get(0);sort(a+1,a+a[0]+1);
for (int i=1;i<=a[0];++i)
if (!vis[i])
{
b[++b[0]]=a[i];
for (int j=i+1;j<=a[0];++j)
if (a[j]%a[i]==0) vis[j]=1;
}
dfs(1,0,1);
printf("%lld\n",ans);
}