[BZOJ 1853] 幸運數字
阿新 • • 發佈:2019-04-06
lse 需要 進行 元組 存在 () http har 算法
[題目鏈接]
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; }
[BZOJ 1853] 幸運數字