版权声明:布呗之路的守望者 https://blog.csdn.net/hypHuangYanPing/article/details/82228696
/**
链接:https://community.topcoder.com/stat?c=problem_statement&pm=10420
题意:lucky number :只包含数字4和7数字;
almostLuckyNumbers:能够被lucky number整除的数字
问[a,b]中存在多少个almostluckynumber;
分析:先预处理出所有的只含4和7的数字 去除冗余的情况后进行容斥;
遵循奇加偶减的性质 暴力容斥原理 枚举选出哪些数能够被ta们的lcm整除
剪枝小优化:可先枚举数字比较大的数字,再选择枚举数字比较小的数字;
这样的话,lcm可以很快的超出区间的范围 这样缩小搜索的深度;
此可作为模板记下;
时间复杂度2^k;
*/
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=1e5+7;
bool vis[maxn];
vector<ll>a,b;
ll l,r,ans;
class TheAlmostLuckyNumbers{
public:
void pre(ll sum){
if(sum>r) return ;
if(sum>0) a.push_back(sum);
pre(sum*10+4);
pre(sum*10+7);
}
ll gcd(ll a,ll b){return b==0?a:gcd(b,a%b);}
void dfs(int step,int flag,ll sum){
if(step==b.size()) { ans+=flag*(r/sum-(l-1)/sum);return ; }//记录的是不能够整除的情况
dfs(step+1,flag,sum);
ll tmp=sum/gcd(b[step],sum);
if((double)b[step]*tmp<=r) dfs(step+1,-flag,b[step]*tmp);
}
ll count(ll p,ll q){
l=p,r=q;
pre(0);
sort(a.begin(),a.end());
for(int i=0;i<a.size();i++){//冗余
if(!vis[i]) {
for(int j=i+1;j<a.size();j++)
if(a[j]%a[i]==0) vis[j]=1;
b.push_back(a[i]);
}
}
reverse(b.begin(),b.end());
dfs(0,1,1);
return (q-p+1)-ans;
}
};