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

本文提供了一种解决BZOJ1853问题的有效算法,通过枚举并筛选出幸运数字,利用降序排列优化时间复杂度,并通过计算不同数量幸运数的最小公倍数的倍数出现次数来求解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

传送门: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);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值