题目:Cirno的完美算数教室
解析:
简单容斥原理。
容易发现
1
0
10
10^{10}
1010内满足条件数不超过
2
10
2^{10}
210个,但是由于计算中如果
x
1
x_1
x1是
x
2
x_2
x2的倍数,那么如果一个数是
x
1
x_1
x1的倍数,那么它同样是
x
2
x_2
x2的倍数,所以我们只用保留
x
2
x_2
x2就行了,这样剔除之后总数会降至几十个,这时候就可以直接搜索。
a
n
s
=
ans=
ans=至少被一个数整除的数的数量
−
-
−至少被两个数整除的数的数量
+
+
+至少被三个数整除的数的数量
…
…
……
……。
复杂度乍一看是错的,但是由于这些数连乘几个之后就会超过上界,所以剪剪枝就行了。
代码:
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int Max=1025;
int l,r,s1,s2,ans;
int a[Max],num[Max],vis[Max];
inline void search(int now)
{
if(now>r) return;
if(now) a[++s1]=now;
search(now*10+2),search(now*10+9);
}
inline void dfs(int now,int sum,int lcm) //now当前数sum奇偶
{
if(now>s2)
{
if(sum&1) ans+=r/lcm-(l-1)/lcm;
else if(sum) ans-=r/lcm-(l-1)/lcm;
return;
}
dfs(now+1,sum,lcm);
int s=lcm*num[now]/__gcd(lcm,num[now]);
if(s>r) return;
dfs(now+1,sum+1,s);
}
signed main()
{
cin>>l>>r;
search(0);
sort(a+1,a+s1+1);
for(int i=1;i<=s1;i++)
{
if(vis[i]) continue;
num[++s2]=a[i];
for(int j=i+1;j<=s1;j++) if(!(a[j]%a[i])) vis[j]=1;
}
dfs(1,0,1);
cout<<ans;
return 0;
}