【BZOJ】1853: [Scoi2010]幸运数字-DFS/容斥

版权声明:转载请附带链接或评论 https://blog.csdn.net/corsica6/article/details/82356241

传送门:bzoj1853


题解

首先枚举出所有范围内的“幸运号码”,再去掉重复的(是某个小的“幸运号码”的倍数的数)后只有900多个。
然后枚举1,2,…,n个幸运数的lcm的倍数的出现个数,再乘上容斥系数即可。
将幸运数降序排列,更快溢出数据范围优化时间复杂度。


代码

#include<bits/stdc++.h>
#define RI register
using namespace std;
typedef long long ll;
const int N=3000;
int tot,cnt,vis[N];
ll a[N],b[N],ans,L,R,tp,ql,qr;

inline bool cmp(const ll&x,const ll&y){return x>y;}
inline ll gcd(ll x,ll y){return (!y)?x:gcd(y,x%y);}

inline void dfs(int num,ll s,ll jd,int des)
{
    if(num==des) {a[++tot]=s;return;}   
    dfs(num+1,s+jd*6,jd*10,des);
    dfs(num+1,s+jd*8,jd*10,des);
}

inline ll cal(ll ys,int cr)
{
    if(!cr) return 0;
    ql=(L-1)/ys;qr=R/ys;
    return max(qr-ql,0LL)*((cr&1)?1:(-1));
}

inline void dfss(int num,ll val,int cr)
{
    if(num>cnt){ans+=cal(val,cr);return;}
    dfss(num+1,val,cr);
    tp=val/gcd(val,b[num]);
    if(b[num]<=R/tp) dfss(num+1,tp*b[num],cr+1);
}

int main(){
    RI int i,j;
    scanf("%lld%lld",&L,&R);
    for(i=2;i<=11;++i) dfs(1,0,1,i);
    for(i=1;i<=tot;++i) if(!vis[i]){
        vis[i]=1;b[++cnt]=a[i];
        for(j=i+1;j<=tot;++j)
          if((!vis[j]) && (a[j]%a[i]==0)) vis[j]=1;
    }
    sort(b+1,b+cnt+1,cmp);
    dfss(1,1,0);
    printf("%lld\n",ans);
}

猜你喜欢

转载自blog.csdn.net/corsica6/article/details/82356241