P2567 [SCOI2010]幸运数字

题目

P2567 [SCOI2010]幸运数字

做法

容斥+剪枝

先预处理幸运数字,别看数据范围这么大,其实也没几个,然后去掉倍数这种

然后处理相似数字,一眼的容斥,递归选数然后求出这些的公倍数容斥一下

玄学剪枝:从大到小排列,若公倍数大于范围退出,加速大于范围的情况

My complete code

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdlib>
#include<string>
#include<cmath>
#include<ctime>
using namespace std;
typedef long long LL;
const int maxn=100000;
LL A,B;
int tot,cnt,ans;
LL a[maxn],num[maxn];
bool visit[maxn];
void First(int dep,int now,LL bit,LL x){
    if(now>dep){
        a[++tot]=bit;
        return;
    }
    First(dep,now+1,bit+(x<<2)+(x<<1),(x<<3)+(x<<1)),
    First(dep,now+1,bit+(x<<3),(x<<3)+(x<<1));
}
inline bool cmp(LL x,LL y){
    return x>y;
}
inline LL Gcd(LL a,LL b){
    while(b){
        LL c=a%b;
        a=b,b=c;
    }
    return a;
}
inline LL Calc(LL l,LL r,LL lcm){
    return r/lcm-(l-1)/lcm;
}
void Dfs(int dep,int now,LL val){
    if(val>B)
        return;
    if(dep>cnt){
        if(now==0)
            return;
        ans+=Calc(A,B,val)*((now&1)?1:-1);
        return;
    }
    Dfs(dep+1,now,val);
    LL lcm=val/Gcd(val,num[dep]);
    if(1.0*lcm*num[dep]<=B)
        Dfs(dep+1,now+1,lcm*num[dep]);
}
int main(){
    scanf("%lld%lld",&A,&B);
    int t1=clock();
    for(int i=1;i<=10;++i)
        First(i,1,0,1);//printf("233");
    for(int i=1;i<=tot;++i){
        if(!visit[i])
            num[++cnt]=a[i];
        for(int j=i+1;j<=tot;++j)
            if(a[j]%a[i]==0)
                visit[j]=true;
    }
    sort(num+1,num+1+cnt,cmp);
    Dfs(1,0,1ll);
    printf("%lld\n",ans);
    return 0;
}/*
1 10000000000
*/
posted @ 2019-01-16 10:42  y2823774827y  阅读(210)  评论(0编辑  收藏  举报