【Luogu】P2567幸运数字(容斥爆搜)

  题目链接

  先预处理出幸运数,把成倍数关系的剔掉,然后用容斥原理搜索一下。

  这里的容斥很像小学学的那个“班上有n个同学,有a个同学喜欢数学,b个同学喜欢语文……”那样。

  

#include<cstdio>
#include<cstdlib>
#include<cctype>
#include<algorithm>
#include<cstring>
#define maxn 200020
using namespace std;
inline long long read(){
    long long num=0,f=1;
    char ch=getchar();
    while(!isdigit(ch)){
        if(ch=='-')    f=-1;
        ch=getchar();
    }
    while(isdigit(ch)){
        num=num*10+ch-'0';
        ch=getchar();
    }
    return num*f;
}

long long q[maxn];int tot;
long long d[maxn];int cnt;
bool vis[maxn];

void find(int deep,long long now){
    if(deep==0){
        q[++tot]=now;
        return;
    }
    find(deep-1,now*10+6);
    find(deep-1,now*10+8);
}

bool cmp(long long a,long long b){    return a>b;    }

long long calc(long long l,long long r,long long e){
    if(l%e==0)    l/=e;
    else l=l/e+1;
    r/=e;
    return r-l+1;
}

long long gcd(long long a,long long b){
    return b==0?a:gcd(b,a%b);
}

long long ans=0;
long long a,b;

void dfs(int deep,int Cnt,long long val){
    if(val>b)    return;
    if(deep>cnt){
        if(Cnt==0)    return;
        ans+=calc(a,b,val)*(Cnt&1?1:-1);
        return;
    }
    dfs(deep+1,Cnt,val);
    long long tmp=val/gcd(val,d[deep]);
    if(1.0*tmp*d[deep]<=b)    dfs(deep+1,Cnt+1,tmp*d[deep]);
}

int main(){
    a=read(),b=read();
    for(int i=1;i<=10;++i)    find(i,0);
    for(int i=1;i<=tot;++i){
        if(vis[i]==0)    d[++cnt]=q[i];
        for(int j=i+1;j<=tot;++j)
            if(q[j]%q[i]==0)    vis[j]=1;
    }
    sort(d+1,d+cnt+1,cmp);
    dfs(1,0,1);
    printf("%lld
",ans);
    return 0;
}
原文地址:https://www.cnblogs.com/cellular-automaton/p/8779831.html