bzoj1853 [Scoi2010]幸运数字

Posted wfj_2048

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了bzoj1853 [Scoi2010]幸运数字相关的知识,希望对你有一定的参考价值。

Description

在中国,很多人都把6和8视为是幸运数字!lxhgww也这样认为,于是他定义自己的“幸运号码”是十进制表示中只包含数字6和8的那些号码,比如68,666,888都是“幸运号码”!但是这种“幸运号码”总是太少了,比如在[1,100]的区间内就只有6个(6,8,66,68,86,88),于是他又定义了一种“近似幸运号码”。lxhgww规定,凡是“幸运号码”的倍数都是“近似幸运号码”,当然,任何的“幸运号码”也都是“近似幸运号码”,比如12,16,666都是“近似幸运号码”。 现在lxhgww想知道在一段闭区间[a, b]内,“近似幸运号码”的个数。

Input

输入数据是一行,包括2个数字a和b

Output

输出数据是一行,包括1个数字,表示在闭区间[a, b]内“近似幸运号码”的个数

Sample Input

【样例输入1】
1 10
【样例输入2】
1234 4321

Sample Output

【样例输出1】
2
【样例输出2】
809

HINT

【数据范围】
对于30%的数据,保证1 < =a < =b < =1000000
对于100%的数据,保证1 < =a < =b < =10000000000

 

正解:搜索+容斥原理。

首先把所有幸运数搜索出来,最多只会有$2046$个。

然后我们考虑容斥原理,即暴力枚举每个数用不用,然后加减一下贡献即可。

但是极限数据跑不过,我们加两个剪枝。

首先我们把所有幸运数从大到小搜索,这样留给后面的状态就会变少。

然后我们把是一个幸运数数的倍数的幸运数去掉,可以发现这是不会影响答案的,并且可以减少状态。

然后注意求$lcm$可能会爆$long \ long$,我们使用$double$即可。这样我们就能通过此题了。

 

 1 #include <bits/stdc++.h>
 2 #define il inline
 3 #define RG register
 4 #define ll long long
 5 
 6 using namespace std;
 7 
 8 ll st[5010],ss[5050],vis[5050],tp,top,ans,a,b;
 9 
10 il ll cmp(const ll &a,const ll &b){ return a>b; }
11 
12 il ll gcd(RG ll a,RG ll b){ return b ? gcd(b,a%b) : a; }
13 
14 il double lcm(RG ll a,RG ll b){ return 1.0*a/gcd(a,b)*b; }
15 
16 il void dfs0(RG ll x,RG ll tot){
17   if (tot>b) return; if (tot) st[++top]=tot;
18   dfs0(x+1,tot*10+6),dfs0(x+1,tot*10+8); return;
19 }
20 
21 il void dfs(RG ll x,RG ll tot,RG ll op){
22   if (x>top){
23     if (tot==1) return;
24     if (op) ans+=b/tot-(a-1)/tot;
25     else ans-=b/tot-(a-1)/tot;
26     return;
27   }
28   dfs(x+1,tot,op); RG double res=lcm(tot,st[x]);
29   if (res>b) return; dfs(x+1,res,op^1); return;
30 }
31 
32 int main(){
33 #ifndef ONLINE_JUDGE
34   freopen("number.in","r",stdin);
35   freopen("number.out","w",stdout);
36 #endif
37   cin>>a>>b,dfs0(1,0);
38   for (RG int i=1;i<top;++i)
39     for (RG int j=i+1;j<=top;++j)
40       if (st[i]%st[j]==0) vis[i]=1;
41       else if (st[j]%st[i]==0) vis[j]=1;
42   for (RG int i=1;i<=top;++i) if (!vis[i]) ss[++tp]=st[i];
43   for (RG int i=1;i<=tp;++i) st[i]=ss[i]; top=tp;
44   sort(st+1,st+top+1,cmp),dfs(1,1,0),cout<<ans; return 0;
45 }

 

以上是关于bzoj1853 [Scoi2010]幸运数字的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ-1853: [Scoi2010]幸运数字 (容斥原理)

AC日记——[SCOI2010]幸运数字 bzoj 1853

BZOJ 1853 Scoi2010 幸运数字

bzoj1853 [Scoi2010]幸运数字

bzoj1853 [Scoi2010]幸运数字

bzoj1853 [Scoi2010]幸运数字