BZOJ 4320: ShangHai2006 Homework
考虑 分块
令 $unit = sqrt(300000)$
对于 小于$x <= unit 的 直接暴力O(unit)维护,O(1) 查询$
对于 大于$x > unit 的 考虑枚举 y = k \cdot x, 再查询 [y, 2y]之间的出现过的最小值,此时的答案为 最小值 - y$
$暴力枚举上去 发现是O(unit)的查询,再考虑维护$
$可以对权值分块进行维护,块内暴力维护,块间作标记$
总的复杂度为$O(n\sqrt{300000})$
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 100010 5 #define M 300010 6 #define unit 450 7 int n = 300000, q, f[unit << 1], g[M], h[unit << 1]; 8 9 void add(int x) 10 { 11 for (int i = 1; i <= unit; ++i) f[i] = min(f[i], x % i); 12 int st = ((x - 1) / unit) * unit + 1, ed = (x - 1) / unit; 13 for (int i = st; i <= x; ++i) g[i] = min(g[i], x); 14 for (int i = 0; i < ed; ++i) h[i] = min(h[i], x); 15 } 16 17 int ask(int x){ return min(g[x], h[(x - 1) / unit]); } 18 19 int query(int x) 20 { 21 if (x <= unit) return f[x]; 22 int res = M; 23 for (int i = 0, j = x; i <= n; j += x) 24 { 25 int t = ask(max(i, 1)); 26 res = min(res, t - i); 27 i = j; 28 } 29 return res; 30 } 31 32 void init() 33 { 34 memset(f, 0x3f, sizeof f); 35 memset(g, 0x3f, sizeof g); 36 memset(h, 0x3f, sizeof h); 37 } 38 39 void Run() 40 { 41 while (scanf("%d", &q) != EOF) 42 { 43 init(); 44 char op[10]; int x; 45 for (int qq = 1; qq <= q; ++qq) 46 { 47 scanf("%s%d", op, &x); 48 if (op[0] == 'A') add(x); 49 else printf("%d\n", query(x)); 50 } 51 } 52 } 53 54 int main() 55 { 56 #ifdef LOCAL 57 freopen("Test.in", "r", stdin); 58 #endif 59 60 Run(); 61 return 0; 62 }