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

Day1

 

简单容斥
找出区间内所有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;
}
posted @ 2017-12-11 17:04  _wsy  阅读(221)  评论(0编辑  收藏  举报