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
",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 }
原文地址:https://www.cnblogs.com/mj-liylho/p/8654711.html