1. 程式人生 > >[BZOJ 1853] 幸運數字

[BZOJ 1853] 幸運數字

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] 幸運數字