P2567 [SCOI2010]幸运数字 DFS+容斥定理
P2567 [SCOI2010]幸运数字
题目描述
在中国,很多人都把6和8视为是幸运数字!lxhgww也这样认为,于是他定义自己的“幸运号码”是十进制表示中只包含数字6和8的那些号码,比如68,666,888都是“幸运号码”!但是这种“幸运号码”总是太少了,比如在[1,100]的区间内就只有6个(6,8,66,68,86,88),于是他又定义了一种“近似幸运号码”。lxhgww规定,凡是“幸运号码”的倍数都是“近似幸运号码”,当然,任何的“幸运号码”也都是“近似幸运号码”,比如12,16,666都是“近似幸运号码”。
现在lxhgww想知道在一段闭区间[a, b]内,“近似幸运号码”的个数。
输入输出格式
输入格式:
输入数据是一行,包括2个数字a和b
输出格式:
输出数据是一行,包括1个数字,表示在闭区间[a, b]内“近似幸运号码”的个数
输入输出样例
输入样例
1 10
输出样例
2
说明
对于100%的数据,保证1<=a<=b<=10000000000
思路:
代码:
1 #include"bits/stdc++.h" 2 #define db double 3 #define ll long long 4 #define cl(x) scanf("%lld",&x) 5 #define pl(x) printf("%lld\n",x) 6 const int N = 1e5 + 5; 7 const int mod = 1e9 + 7; 8 using namespace std; 9 ll a[N],b[N]; 10 bool v[N]; 11 int m=0,n=0; 12 ll l,r,ans=0; 13 ll gcd(ll x,ll y){ 14 return y==0?x:gcd(y,x%y); 15 } 16 void init(ll x){ 17 if(x>r) return ; 18 else if(x>0) a[++m]=x;//0不加入 19 init(x*10+6); 20 init(x*10+8); 21 } 22 void dfs(int x,int y,ll z)//表示:前x个数字中选y个数字时的lcm为z 23 { 24 if(x==n){ 25 if(y&1) ans+=r/z-(l-1)/z;//奇数加 26 if(y%2==0&&y!=0) ans-=r/z-(l-1)/z;//偶数减 27 return; 28 } 29 dfs(x+1,y,z); 30 ll s=z/gcd(a[x+1],z); 31 if((db(s)*a[x+1])<=r) dfs(x+1,y+1,a[x+1]*s);//一个剪枝:lcm<=r 32 } 33 int main() 34 { 35 cl(l),cl(r); 36 init(0); 37 sort(a+1,a+m+1); 38 for(int i=1;i<=m;i++){//去掉内部倍数情况 39 if(!v[i]){ 40 b[++n]=a[i]; 41 for(int j=i+1;j<=m;j++) 42 if(a[j]%a[i]==0) v[j]=1; 43 } 44 } 45 for(int i=1;i<=n;i++) a[n+1-i]=b[i];//数字从大到小排 46 dfs(0,0,1); 47 pl(ans); 48 return 0; 49 }