[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; }