bzoj1853[Scoi2010]幸运数字 容斥
1853: [Scoi2010]幸运数字
Time Limit: 2 Sec Memory Limit: 64 MB
Submit: 3027 Solved: 1128
[Submit][Status][Discuss]
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
Source
简单容斥
找出区间内所有6和8构成的数,筛出他们的倍数,用ans+-
#include<cstdio> #include<iostream> #include<algorithm> #include<cstring> #define ll long long #define N 5000 using namespace std; ll a,b,c[N],d[N],ans;int vis[N],cnt,tot; void predfs(int pos,ll val){ if(!pos){ if(val<=b) c[++cnt]=val; return; } predfs(pos-1,val*10+6); predfs(pos-1,val*10+8); } bool cmp(ll a,ll b){return a>b;} ll gcd(ll a,ll b){ if(!b)return a; return gcd(b,a%b); } void dfs(int u,ll val,int ok){ if(u>tot){ if(ok&1)ans+=b/val-(a-1)/val; else if(ok)ans-=b/val-(a-1)/val; return; } dfs(u+1,val,ok); ll g=gcd(val,d[u]); ll lcm=val/g*d[u]; if(lcm<0||lcm>b)return; dfs(u+1,lcm,ok+1); } int main(){ cin>>a>>b; for(int i=1;i<=10;i++) predfs(i,0); for(int i=1;i<=cnt;i++){ if(vis[i])continue; int fg=0;d[++tot]=c[i]; for(int j=i+1;j<=cnt;j++) if(c[j]%c[i]==0)vis[j]=1; } sort(d+1,d+1+tot,cmp); dfs(1,1,0); cout<<ans; return 0; }
If you live in the echo,
your heart never beats as loud.
如果你生活在回声里,
你的心跳声永远不会轰鸣作响。