考虑 分块

 

令 $unit = sqrt(300000)$

对于 小于$x <= unit 的 直接暴力O(unit)维护,O(1) 查询$

对于 大于$x > unit 的 考虑枚举 y = k \cdot x, 再查询 [y, 2y]之间的出现过的最小值,此时的答案为 最小值 - y$

$暴力枚举上去 发现是O(unit)的查询,再考虑维护$

$可以对权值分块进行维护,块内暴力维护,块间作标记$

总的复杂度为$O(n\sqrt{300000})$

BZOJ 4320: ShangHai2006 Homework_分块BZOJ 4320: ShangHai2006 Homework_c++_02
 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 }
View Code