[BZOJ 1853] 幸运数字

[题目链接]

         https://www.lydsy.com/JudgeOnline/problem.php?id=1853

[算法]

        首先 , [L , R]区间的答案 = [1 , R]区间答案 - [1 , L - 1]区间答案

        考虑可以预处理[1 , R]中的“幸运数字”和[1 , L - 1]中的幸运数字 , 然后用容斥原理分别计算

        然而直接搜索是会超时的 , 我们需要进行一些剪枝 :

        1. 当最小公倍数 > R时退出

        2. 当存在二元组(i , j) , 满足Ai(mod Aj) = 0时 , Ai无用

        时间复杂度 : O(2 ^ CNT log V)(CNT为“幸运数字”个数 , 实际运行远远达不到这个上界)

[代码]

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef long double ld;
typedef unsigned long long ull;
#define N 100010

#define rint register int

int len , L;
ll a , b , l , r , ret , nowlcm;
ll A[N] , B[N];
bool tag[N];

template <typename T> inline void chkmax(T &x , T y) { x = max(x , y); }
template <typename T> inline void chkmin(T &x , T y) { x = min(x , y); }
template <typename T> inline void read(T &x)
{
    T f = 1; x = 0;
    char c = getchar();
    for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
    for (; isdigit(c); c = getchar()) x = (x << 3) + (x << 1) + c - '0';
    x *= f;
}
inline void dfs(ll now)
{
    if (now > r) return;
    if (now > 0) A[++len] = now;
    dfs(now * 10 + 6);
    dfs(now * 10 + 8);
}
inline ll gcd(ll x , ll y)
{
    if (y == 0) return x;
    else return gcd(y , x % y);
}
inline ll lcm(ll x , ll y)
{
    return x / gcd(x , y) * y;
}
inline bool check(ll x , ll y)
{
    ll X = x / (ll)1e9 ,
       Y = y / (ll)1e9;
    if (X * Y) return false;
    if (x * y / gcd(x , y) > r) return false;
    return true;
}
inline void work(int depth , int cnt)
{
    if (depth > L)
    {
        if (!cnt) return;
        if (cnt & 1) ret += r / nowlcm - (l - 1) / nowlcm;
        else ret -= r / nowlcm - (l - 1) / nowlcm;
    } else
    {
        work(depth + 1 , cnt);
        ll tmp = nowlcm;
        if (check(nowlcm , B[depth])) 
        {
            nowlcm = lcm(nowlcm , B[depth]);
            work(depth + 1 , cnt + 1);
            nowlcm = tmp;
        }
    }
}
inline ll calc(ll x)
{
    len = 0;
    l = a; r = b;
    dfs(0);
    sort(A + 1 , A + len + 1 , greater< int >());
    for (rint i = 1; i <= len; ++i) tag[i] = false;
    L = 0;
    for (rint i = 1; i <= len; ++i)
    {
        for (rint j = 1; j <= len; ++j)
        {
            if (i != j && A[j] % A[i] == 0)
                tag[j] = true;
        }
    }
    for (int i = 1; i <= len; ++i)
        if (!tag[i]) B[++L] = A[i];
    int tmp = L;
    L = 0;
    for (rint i = 1; i <= tmp; ++i)
    {
        if (B[i] >= r / 3) ret += r / B[i] - (l - 1) / B[i];
        else B[++L] = B[i];
    }
    nowlcm = 1;
    work(1 , 0);
    return ret;
}

int main()
{
    
    read(a); read(b);
    printf("%lld\n" , calc(b));
    
    return 0;
}

猜你喜欢

转载自www.cnblogs.com/evenbao/p/10659969.html