1. 程式人生 > >bzoj1853 [Scoi2010]幸運數字

bzoj1853 [Scoi2010]幸運數字

範圍 () inline main res 號碼 tdi long long sin

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]幸運數字