版权声明:转载请附带链接或评论 https://blog.csdn.net/corsica6/article/details/82356241
传送门:bzoj1853
题解
首先枚举出所有范围内的“幸运号码”,再去掉重复的(是某个小的“幸运号码”的倍数的数)后只有900多个。
然后枚举1,2,…,n个幸运数的lcm的倍数的出现个数,再乘上容斥系数即可。
将幸运数降序排列,更快溢出数据范围优化时间复杂度。
代码
#include<bits/stdc++.h>
#define RI register
using namespace std;
typedef long long ll;
const int N=3000;
int tot,cnt,vis[N];
ll a[N],b[N],ans,L,R,tp,ql,qr;
inline bool cmp(const ll&x,const ll&y){return x>y;}
inline ll gcd(ll x,ll y){return (!y)?x:gcd(y,x%y);}
inline void dfs(int num,ll s,ll jd,int des)
{
if(num==des) {a[++tot]=s;return;}
dfs(num+1,s+jd*6,jd*10,des);
dfs(num+1,s+jd*8,jd*10,des);
}
inline ll cal(ll ys,int cr)
{
if(!cr) return 0;
ql=(L-1)/ys;qr=R/ys;
return max(qr-ql,0LL)*((cr&1)?1:(-1));
}
inline void dfss(int num,ll val,int cr)
{
if(num>cnt){ans+=cal(val,cr);return;}
dfss(num+1,val,cr);
tp=val/gcd(val,b[num]);
if(b[num]<=R/tp) dfss(num+1,tp*b[num],cr+1);
}
int main(){
RI int i,j;
scanf("%lld%lld",&L,&R);
for(i=2;i<=11;++i) dfs(1,0,1,i);
for(i=1;i<=tot;++i) if(!vis[i]){
vis[i]=1;b[++cnt]=a[i];
for(j=i+1;j<=tot;++j)
if((!vis[j]) && (a[j]%a[i]==0)) vis[j]=1;
}
sort(b+1,b+cnt+1,cmp);
dfss(1,1,0);
printf("%lld\n",ans);
}