POI2014解题报告

穷酸博主没有bz权限号, 也不会去$poi$官网, 在某咕刷的$poi$,按照某咕的难度排序刷, poi~


$Luogu3572 PTA-Little Bird$

单调队列, 队列内按照 步数为第一关键字递增, 高度为第二关键字递减

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define rd read()
 5 #define R register
 6 #define N 1000005
 7 using namespace std;
 8 
 9 int n, k, Q;
10 int d[N], f[N], q[N];
11 
12 inline int read() {
13     int X = 0, p = 1; char c = getchar();
14     for (; c > '9' || c < '0';c = getchar())
15         if (c == '-') p = -1;
16     for (; c >= '0' && c <= '9'; c = getchar())
17         X = X * 10 + c - '0';
18     return X * p;
19 }
20 
21 int main()
22 {
23     n = rd;
24     for (R int i = 1; i <= n; ++i) d[i] = rd;
25     Q = rd; 
26     for (; Q; Q--) {
27         k = rd;
28         int l = 1, r = 1;
29         q[l] = 1;
30         for (R int i = 2; i <= n; ++i) {
31             while (l <= r && q[l] < i - k) l++;
32             f[i] = f[q[l]] + (d[q[l]] <= d[i] ? 1 : 0);
33             while (l <= r && (f[q[r]] > f[i] || (f[q[r]] == f[i] && d[q[r]] <= d[i]))) r--;
34             q[++r] = i;
35         }
36         printf("%d\n", f[n]);
37     }
38 }
View Code

$Luogu3566KLO-Bricks$

贪心, 优先用右端点$ed$的颜色的来填, 如果$ed$用光了或者上一个颜色是$ed$, 则选取剩下来个数最多的去填

个数最多可以用线段树维护

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define rd read()
 5 #define N 1000005
 6 using namespace std;
 7 typedef pair<int, int > P;
 8 
 9 int n, m, cnt[N], st, ed, a[N];
10 
11 int read() {
12     int X = 0, p = 1; char c = getchar();
13     for (; c > '9' || c < '0'; c = getchar())
14         if (c == '-') p = -1;
15     for (; c >= '0' && c <= '9'; c = getchar())
16         X = X * 10 + c - '0';
17     return X * p;
18 }
19 
20 void up(int &A, int B) {
21     if (A < B) A = B;
22 }
23 
24 P cmax(P A, P B) {
25     return A > B ? A : B;
26 }
27 
28 namespace SegT {
29 #define lson nd << 1
30 #define rson nd << 1 | 1
31 #define mid ((l + r) >> 1)
32     P Max[N << 2];
33     
34     void pushup(int nd) {
35         Max[nd] = cmax(Max[lson], Max[rson]);
36     }
37 
38     void build(int l, int r, int nd) {
39         if (l == r) {
40             Max[nd] = P(cnt[l], l); return;
41         }
42         build(l, mid, lson); build(mid + 1, r, rson);
43         pushup(nd);
44     }
45 
46     void modify(int c, int l, int r, int nd) {
47         if (l == r) {
48             Max[nd].first-- ; return;
49         }
50         if (c <= mid) modify(c, l, mid, lson);
51         else modify(c, mid + 1, r, rson);
52         pushup(nd);
53     }
54 
55     P query(int L, int R, int l, int r, int nd) {
56         if (L > R) return P(0, 0);
57         if (L <= l && r <= R) return Max[nd];
58         P tmp = P(0, 0);
59         if (mid >= L)
60             tmp = cmax(tmp, query(L, R, l, mid, lson));
61         if (mid < R)
62             tmp = cmax(tmp, query(L, R, mid + 1, r, rson));
63         return tmp;
64     }
65 }using namespace SegT;
66 
67 int main()
68 {
69     m = rd; st = rd; ed = rd;
70     for (int i = 1; i <= m; ++i)
71         n += (cnt[i] = rd);
72     cnt[st] --; cnt[ed] --;
73     a[1] = st; a[n] = ed;
74     build(1, m, 1);
75     for (int i = 2; i < n; ++i) {
76         if (cnt[ed] && a[i - 1] != ed) {
77             a[i] = ed;
78             cnt[a[i]]--;
79             modify(a[i], 1, m, 1);
80         } else {
81             P tmp = query(1, a[i - 1] - 1, 1, m, 1);
82             tmp = cmax(tmp, query(a[i - 1] + 1, m, 1, m, 1));
83             if (tmp.first == 0) return printf("0"), 0;
84             a[i] = tmp.second;
85             cnt[a[i]]--;
86             modify(a[i], 1, m, 1);
87         }
88     }
89     if (a[n - 1] == a[n]) 
90         return printf("0"), 0;
91     printf("%d", a[1]);
92     for (int i = 2; i <= n; ++i)
93         printf(" %d", a[i]);
94     return 0;
95 }
View Code

$Luogu3575DOO-Around the world$

双指针扫一遍, 找到从 $i$ 往前最多能飞多少格。 并记录步数和起始位置。 当起始位置和当前位置相距不少于N, 则更新答案。

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define rd read()
 5 #define N 2000005
 6 #define R register
 7 using namespace std;
 8 
 9 int n, m, f[N], head[N], maxn, a[N];
10 
11 int read() {
12     int X = 0, p = 1; char c = getchar();
13     for (; c > '9' || c < '0'; c = getchar())
14         if (c == '-') p = -1;
15     for (; c >= '0' && c <= '9'; c = getchar())
16         X = X * 10 + c - '0';
17     return X * p;
18 }
19 
20 void cmax(int &A, int B) {
21     if (A < B) A = B;
22 }
23 
24 void cmin(int &A, int B) {
25     if (A > B) A = B;
26 }
27 
28 void work(int d) {
29     if (d < maxn) {
30         puts("NIE"); return;
31     }
32     int ans = n;
33     for (R int i = n + 1, j = 1; i <= 2 * n; ++i) {
34         while (a[i] - a[j] > d) j++;
35         f[i] = f[j] + 1, head[i] = head[j];
36         if (i - head[i] >= n) cmin(ans, f[i]);
37     }
38     printf("%d\n", ans);
39 }
40 
41 int main()
42 {
43     n = rd; m = rd;
44     for (R int i = 1; i <= n; ++i) 
45         a[i] = a[i + n] = rd,
46         cmax(maxn, a[i]),
47         head[i] = i;
48     for (R int i = 1; i <= 2 * n; ++i)
49         a[i] += a[i - 1];
50     for (R int i = 1; i <= m; ++i) work(rd);
51 }
View Code

$Luogu3565Hotels$

枚举根节点为中心, 在根的不同儿子的子树中找$3$个相同深度的点的方案数。 时间复杂度$O(N^2)$,

不过好像用长链剖分可以做到$O(N)$。。。老年选手也懒得去学了唔

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define rd read()
 5 #define N 5005
 6 #define ll long long
 7 #define R register
 8 using namespace std;
 9 
10 int head[N], tot, dep[N], g[N], n;
11 ll ans, f[N][3];
12 
13 struct edge {
14     int nxt, to;
15 }e[N << 1];
16 
17 inline int read() {
18     int X = 0, p = 1; char c = getchar();
19     for (; c > '9' || c < '0'; c = getchar())
20         if (c == '-') p = -1;
21     for (; c >= '0' && c <= '9'; c = getchar())
22         X = X * 10 + c - '0';
23     return X * p;
24 }
25 
26 void add(int u, int v) {
27     e[++tot].to = v;
28     e[tot].nxt = head[u];
29     head[u] = tot;
30 }
31 
32 void cmax(int &A, int B) {
33     if (A < B) A = B;
34 }
35 
36 void dfs(int u, int fa) {
37     g[dep[u]] ++;
38     for (R int i = head[u]; i; i = e[i].nxt) {
39         int nt = e[i].to;
40         if (nt == fa) continue;
41         dep[nt] = dep[u] + 1;
42         dfs(nt, u);
43     }
44 }
45 
46 int main()
47 {
48     n = rd; 
49     for (int i = 1; i < n; ++i) {
50         int u = rd, v = rd;
51         add(u, v); add(v, u);
52     }
53     for (R int rt = 1; rt <= n; ++rt) {
54         dep[rt] = 1;
55         memset(f, 0, sizeof(f));
56         for (R int i = head[rt]; i; i = e[i].nxt) {
57             memset(g, 0, sizeof(g));
58             dep[e[i].to] = 2;
59             dfs(e[i].to, rt);
60             for (R int j = 2; j; --j)
61                 for (R int k = 1; k <= n; ++k)
62                     f[k][j] += f[k][j - 1] * g[k];
63             for (R int k = 1; k <= n; ++k)
64                 f[k][0] += g[k];
65         }
66         for (R int i = 1; i <= n; ++i)
67             ans += f[i][2];
68     }
69     printf("%lld\n", ans);
70 }
View Code

$Luogu3580Freight$

列车肯定是 分批, 一批过去再回来, 才轮到下一批。

然后就开始$DP$, 设$F[i]$ 为前 $i$ 辆列车回来的最早时间, 同时为了防止不同列车同时出发, 令$t[i] = max(t[i], t[i-1] + 1)$

有状态转移方程:

  $f[i] \ = \ min( \ max(f[j] + i -j-1, t[i])+2 \times S + i - j - 1)$

移项得:

  $f[i] \ = \ 2 \times S + 2 \times i -1 \ + \ min( \ max(f[j] - j - 1, t[i] - i)-j)$

由于 $f[j] - j-1$ 和 $t[i] - i$ 是不下降的, 所以用单调队列找到第一个分界点, 并且队列 除第一位 按照 $f[j]-2 \times j - 1$ 递增

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define rd read()
 5 #define N 1000005
 6 #define R register
 7 #define ll long long
 8 using namespace std;
 9 
10 int n, t[N], q[N], S;
11 ll f[N];
12 
13 inline int read() {
14     int X = 0, p = 1; char c = getchar();
15     for (; c > '9' || c < '0'; c = getchar())
16         if (c == '-') p = -1;
17     for (; c >= '0' && c <= '9'; c = getchar())
18         X = X * 10 + c - '0';
19     return X * p;
20 }
21 
22 inline int cmax(int A, int B) {
23     return A > B ? A : B;
24 }
25 
26 template<typename T>
27 inline void down(T &A, T B) {
28     if (A > B) A = B;
29 }
30 
31 int main()
32 {
33     n = rd; S = rd;
34     for (R int i = 1; i <= n; ++i) 
35         t[i] = cmax(rd, t[i - 1] + 1);
36     int l = 1, r = 1;
37     for (R int i = 1; i <= n; ++i) {
38         while (l < r && f[q[l + 1]] - q[l + 1] - 1<= t[i] - i) l++;
39         f[i] = 1LL * t[i] + i - q[l] + 2 * S - 1;
40         if (l < r) down(f[i], f[q[l + 1]] - 2 * q[l + 1] - 1 + 2 * S + 2 * i - 1);
41         while (l < r && f[q[r]] - 2 * q[r] >= f[i] - 2 * i) r--;
42         q[++r] = i;
43     }
44     printf("%lld\n", f[n]);
45 }
View Code

$Luogu3574FarmCraft$

贪心排序+树形DP 

我们可以递归求出每颗子树所需要的最大时间,

子节点到父节点的转移方程:

  $f[u] \ = \ max(2 \times \sum\limits_{k=1}^{i-1}sz[k] + f[i]+1)$ , 父节点 $f[u]$ 初始为 $a[u]$

根据贪心, 把子树按照$2 \times sz[i]-f[i]$进行排序(证明挺简单的, 邻项交换 就可以证出)

由于根节点是要最后安装电脑的, $f[1] = max(f[1], a[1] + 2 \times (sz[1] - 1) )$

最后输出$f[1]$, 复杂度$O(NlogN)$

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<vector>
 5 #define N 500005
 6 #define rd read()
 7 using namespace std;
 8 
 9 int head[N], tot, n, f[N], sz[N], a[N];
10 vector<int> v[N];
11 
12 struct edge {
13     int nxt, to;
14 }e[N << 1];
15 
16 inline int read() {
17     int X = 0, p = 1; char c = getchar();
18     for (; c > '9' || c < '0'; c = getchar())
19         if (c == '-') p = -1;
20     for (; c >= '0' && c <= '9'; c = getchar())
21         X = X * 10 + c - '0';
22     return X * p;
23 }
24 
25 void add(int fr, int to) {
26     e[++tot].to = to;
27     e[tot].nxt = head[fr];
28     head[fr] = tot;
29 }
30 
31 int cmp(int A, int B) {
32     return 2 * sz[A] - f[A] < 2 * sz[B] - f[B];
33 }
34 
35 void dfs(int u, int fa) {
36     for (int i = head[u]; i; i = e[i].nxt) {
37         int nt = e[i].to;
38         if (nt == fa) continue;
39         dfs(nt, u);
40         v[u].push_back(nt);
41     }
42 }
43 
44 void cmax(int &A, int B) {
45     if (A < B) A = B;
46 }
47 
48 void dp(int u) {
49     sz[u] = 1;
50     f[u] = a[u];
51     for (int i = 0, up = v[u].size(); i < up; ++i) {
52         int nt = v[u][i];
53         dp(nt);
54     }
55     sort(v[u].begin(), v[u].end(), cmp);
56     for (int i = 0, up = v[u].size(); i < up; ++i) {
57         int nt = v[u][i];
58         cmax(f[u], 2 * sz[u] + f[nt] - 1);
59         sz[u] += sz[nt];
60     }
61 }
62 
63 int main()
64 {
65     n = rd;
66     for (int i = 1; i <= n; ++i) a[i] = rd;
67     for (int i = 1; i < n; ++i) {
68         int fr = rd, to = rd;
69         add(fr, to); add(to, fr);
70     }
71     dfs(1, 0); dp(1);
72     cmax(f[1], 2 * (n - 1) + a[1]);
73     printf("%d\n", f[1]);
74 }
View Code

$Luogu3570Criminals$

挺早前就做了的题。。。看不惯当时的毒瘤代码, 空格有时有, 有时没有。

就是一个链表乱搞, 就不贴代码丢脸了(捂脸)


$Luogu3567Couriers$

主席树模板题

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define rd read()
 5 using namespace std;
 6 
 7 const int N = 1e5;
 8 
 9 int lson[N * 100], rson[N * 100], sum[N * 100];
10 int a[N * 10], n, m, root[N * 10], b[N * 10], tot, cnt;
11 
12 int read() {
13     int X = 0, p = 1; char c = getchar();
14     for(; c > '9' || c < '0'; c = getchar()) if(c == '-') p = -1;
15     for(; c >= '0' && c <= '9'; c = getchar()) X = X * 10 +  c - '0';
16     return X * p;
17 }
18 
19 int fd(int x) {
20     return lower_bound(b + 1, b + 1 + tot, x) - b;
21 }
22 
23 void build0(int &o, int l, int r) {
24     o = ++cnt;
25     if(l == r) return;
26     int mid = (l + r) >> 1;
27     build0(lson[o], l, mid);
28     build0(rson[o], mid + 1, r);
29 }
30 
31 void build(int last, int &o, int pos, int l, int r) {
32     o = ++cnt;
33     sum[o] = sum[last] + 1;
34     lson[o] = lson[last];
35     rson[o] = rson[last];
36     if(l == r)
37         return;
38     int mid = (l + r) >> 1;
39     if(pos <= mid)
40         build(lson[last], lson[o], pos, l, mid);
41     else 
42         build(rson[last], rson[o], pos, mid + 1, r);
43 }
44 
45 int query(int last, int now, int k, int l, int r) {
46     if(l == r)
47         return (2 * (sum[now] - sum[last]) > k) ? l : 0;
48     int mid = (l + r) >> 1;
49     if(2 * (sum[lson[now]] - sum[lson[last]]) > k)
50         return query(lson[last], lson[now], k, l, mid);
51     else 
52         return query(rson[last], rson[now], k, mid + 1, r);
53 }
54 
55 int main()
56 {
57     n = rd; m = rd;
58     for(int i = 1; i <= n; ++i)
59         b[i] = a[i] = rd;
60     sort(b + 1, b + 1 + n);
61     tot = unique(b + 1, b + 1 + n) - b - 1;
62     for(int i = 1; i <= n; ++i) 
63         build(root[i - 1], root[i], fd(a[i]), 1, tot);
64     for(int i = 1; i <= m; ++i) {
65         int l = rd, r = rd, ans;
66         ans = query(root[l - 1], root[r], r - l + 1, 1, tot);
67         printf("%d\n", b[ans]);
68     }
69 }
View Code

$Luogu3572Ant colony$

倍增LCA+二分查找

$f[i][j]$ 表示 $i$ 的 $2^j$ 级祖先, $g[i][j]$ 表示从i 到 $f[i][j]$ 要分支成几份。 另外$g[i][j]$ 可能非常大, 最高约是 $3$的几万次方, 所以如果$g[i][j] \times k > a[m]$,直接赋为$-1$

然后就可以倍增求要几个分支,设分支数为 $x$, 则最后被吃掉的蚂蚁数就是 数组a中  $k \times x<=  <=(k + 1) \times -1$的个数, 二分查找即可。

时间复杂度为$O(NlogN)$, (做POI习惯性卡常数了

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #define rd read()
  5 #define N 1000005
  6 #define ll long long
  7 #define R register
  8 using namespace std;
  9 
 10 const int base = 20;
 11 
 12 int n, m, k, tot, st, ed;
 13 int head[N], a[N], f[N][base], d[N], leaf[N], cnt, dep[N];
 14 ll g[N][base], ans;
 15 bool in[N];
 16 
 17 struct edge {
 18     int nxt, to;
 19 }e[N << 1];
 20 
 21 inline int read() {
 22     int X = 0, p = 1; char c = getchar();
 23     for (; c > '9' || c < '0'; c = getchar())
 24         if (c == '-') p = -1;
 25     for (; c >= '0' && c <= '9'; c = getchar())
 26         X = X * 10 + c - '0';
 27     return X * p;
 28 }
 29 
 30 inline void add(int u, int v) {
 31     e[++tot].to = v;
 32     e[tot].nxt = head[u];
 33     head[u] = tot;
 34 }
 35 
 36 void dfs(int u, bool flag) {
 37     in[u] = flag;
 38     for (R int i = head[u]; i; i = e[i].nxt) {
 39         R int nt = e[i].to;
 40         if (nt == f[u][0]) continue;
 41         f[nt][0] = u;
 42         g[nt][0] = (d[nt] - 1) ? d[nt] - 1 : 1;
 43         dep[nt] = dep[u] + 1;
 44         if ((u == e[1].to && nt == e[2].to) || (nt == e[1].to && u == e[2].to))
 45             dfs(nt, true);
 46         else dfs(nt, flag);
 47     }
 48 }
 49 
 50 inline int cal(int x) {
 51     int maxn = upper_bound(a + 1, a + 1 + m, 1LL * (k + 1) * x - 1) - a,
 52     minn = lower_bound(a + 1, a + 1 + m, k * x) - a;
 53     return maxn - minn;
 54 }
 55 
 56 int LCA(R int x, R int y) {
 57     ll res = 1;
 58     if (dep[x] < dep[y]) swap(x, y);
 59     for (R int j = base - 1; ~j; --j)
 60         if (dep[f[x][j]] >= dep[y]) {
 61             res *= g[x][j];
 62             if (res * k > a[m] || res < 0) return -1;
 63             x = f[x][j];
 64         }
 65     if (x == y) {
 66         res *= g[x][0];
 67         if (res * k > a[m] || res < 0) return -1;
 68         else return res;
 69     }
 70     for (R int j = base - 1; ~j; --j)
 71         if (f[x][j] != f[y][j]) {
 72             res *= g[x][j];
 73             res *= g[y][j];
 74             if (res * k > a[m] || res < 0) return -1;
 75             x = f[x][j];
 76             y = f[y][j];
 77         }
 78     res *= g[x][1] * g[y][0];
 79     if (res * k > a[m] || res < 0) return -1;
 80     return res;
 81 }
 82 
 83 void work(int x) {
 84     R int tmp = LCA(x, in[x] ? ed : st);
 85     if (tmp != -1) ans += 1LL * cal(tmp) * k;
 86 }
 87 
 88 int main()
 89 {
 90     n = rd; m = rd; k = rd;
 91     for (R int i = 1; i <= m; ++i)
 92         a[i] = rd;
 93     for (R int i = 1; i < n; ++i) {
 94         int u = rd, v = rd;
 95         add(u, v); add(v, u);
 96         d[u] ++; d[v] ++;
 97     }
 98     dep[1] = 1;
 99     dfs(1, false);
100     g[1][0] = (d[1] - 1) ? d[1] - 1 : 1;
101     sort(a + 1, a + 1 + m);
102     if (dep[e[1].to] > dep[e[2].to]) st = e[2].to, ed = e[1].to;
103     else st = e[1].to, ed = e[2].to;
104     for (R int i = 1; i <= n; ++i)
105         if (d[i] == 1) leaf[++cnt] = i;
106     for (R int j = 1; j < base; ++j)
107         for (R int i = 1; i <= n; ++i) {
108             f[i][j] = f[f[i][j - 1]][j - 1],
109             g[i][j] = g[i][j - 1] * g[f[i][j - 1]][j - 1];
110             if (g[i][j] * k > a[m]) g[i][j] = -1;
111             else if (g[i][j] < 0) g[i][j] = -1;
112         }
113     for (R int i = 1; i <= cnt; ++i)
114         work(leaf[i]);
115     printf("%lld\n", ans);
116 }
View Code

$Luogu3564Salad Bar$

树状数组

若$s[i]=='j'$, 则赋为 $-1$, 若为$'p'$, 则赋为 $1$。 定义 $sum$为前缀和。

则一个字符串 $[j,i]$ 从前往后 的$1$的个数 不少于 $-1$的个数, 则满足 $sum[j-1] <= sum[k]$ $(j<=k<=i)$ 恒成立。

根据这一点, 若要知道最多往后到哪里, 只需往后找到第一个 $i$,$sum[i]>sum[j]$。 单调栈$O(N)$即可维护。 往前同理可得。

我们设从 $i$往后最多到 $R[i]$, 往前最多到 $L[i]$。 一个字符串 $[j,i]$ 满足条件 必须使 $R[j]>=i && L[i]<=j$

我们只需要先把 $i$ 按照 $R[i]$从小往大排序,用树状数组维护即可。

时间复杂度$O(NlogN)$

  1 #include<cstdio>
  2 #include<cstring>
  3 #include<algorithm>
  4 #define rg register
  5 #define rd read()
  6 #define N 1000005
  7 using namespace std;
  8 
  9 int a[N], b[N], n, pre[N], nxt[N];
 10 int st[N], tp, Max[N], ans;
 11 char s[N];
 12 
 13 struct node {
 14     int id, L, R;
 15     bool operator < (const node &A) const {
 16         return R < A.R;
 17     }
 18 }t[N];
 19 
 20 int read() {
 21     int X = 0, p = 1; char c = getchar();
 22     for (; c > '9' || c < '0'; c = getchar())
 23         if (c == '-') p = -1;
 24     for (; c >= '0' && c <= '9'; c = getchar())
 25         X = X * 10 + c - '0';
 26     return X * p;
 27 }
 28 
 29 void init() {
 30     for (rg int i = 1; i <= n + 1; ++i) {
 31         int pr = 0;
 32         while (tp) {
 33             if (b[st[tp]] >= b[i]) tp--;
 34             else {
 35                 pr = st[tp]; break;
 36             }
 37         }
 38         pre[i] = pr;
 39         st[++tp] = i;
 40     }
 41     tp = 0;
 42     for (rg int i = n; ~i; --i) {
 43         int nt = n + 1;
 44         while (tp) {
 45             if (a[st[tp]] >= a[i]) tp--;
 46             else {
 47                 nt = st[tp]; break;
 48             }
 49         }
 50         nxt[i] = nt;
 51         st[++tp] = i;
 52     }
 53 }
 54 
 55 inline int cmin(int A, int B) {
 56     return A > B ? B : A;
 57 }
 58 
 59 inline int cmax(int A, int B) {
 60     return A > B ? A : B;
 61 }
 62 
 63 inline void up(int &A, int B) {
 64     if (A < B) A = B;
 65 }
 66 
 67 int lowbit(int x) {
 68     return x & -x;
 69 }
 70 
 71 void add(int x, int val) {
 72     for (; x <= n; x += lowbit(x))
 73         up(Max[x], val);
 74 }
 75 
 76 int query(int x) {
 77     int res = 0;
 78     for (; x; x -= lowbit(x))
 79         up(res, Max[x]);
 80     return res;
 81 }
 82 
 83 int main()
 84 {
 85     n = rd;
 86     scanf("%s", s + 1);
 87     for (rg int i = 1; i <= n; ++i) 
 88         a[i] = a[i - 1] + (s[i] == 'p' ? 1 : -1);
 89     for (rg int i = n; i; --i)
 90         b[i] = b[i + 1] + (s[i] == 'p' ? 1 : -1);
 91     init();
 92     for (rg int i = 1; i <= n; ++i) 
 93         pre[i] = pre[i + 1] + 1;
 94     for (rg int i = n; i; --i)
 95         nxt[i] = nxt[i - 1] - 1;
 96     for (rg int i = 1; i <= n; ++i) {
 97         t[i].id = i;
 98         t[i].L = pre[i];
 99         t[i].R = nxt[i];
100     }
101     sort(t + 1, t + 1 + n);
102     for (rg int i = 1, j = 1; i <= n; ++i) {
103         while (j <= n && j <= t[i].R) add(pre[j], j), j++;
104         int res = query(t[i].id);
105         up(ans, res - t[i].id + 1);
106     }
107     printf("%d\n", ans);
108 }
View Code

$Luogu3579Solar Panels$

整除分块枚举。。。

真的没有想到会这么简单。

$\left\lfloor\dfrac{1}{2}\right\rfloor$

要使一个数 $p$ 满足 条件, 则 存在$x, y$, $a<=x \times p<=b\ \&\&\ c<=y \times p <=d$

把$p$ 除掉 则

  $$\left\lceil\dfrac{a}{p}\right\rceil <=x <=\left\lfloor\dfrac{b}{p}\right\rfloor$$

  $$\left\lceil\dfrac{c}{p}\right\rceil <=y <=\left\lfloor\dfrac{d}{p}\right\rfloor$$

把向上取整变为向下取整:

  $\left\lfloor\dfrac{a+p-1}{p}\right\rfloor <= \left\lfloor\dfrac{b}{p}\right\rfloor$

  $\left\lfloor\dfrac{b+p-1}{p}\right\rfloor <= \left\lfloor\dfrac{d}{p}\right\rfloor$

然后就变成了 :

  $\left\lfloor\dfrac{a-1}{p}\right\rfloor < \left\lfloor\dfrac{b}{p}\right\rfloor$

  $\left\lfloor\dfrac{b-1}{p}\right\rfloor < \left\lfloor\dfrac{d}{p}\right\rfloor$

最后整除分块。 只需按照 $b/p$和$d/p$ 相同时进行分类。 这样能使 $b/p$ 和 $d/p$相等的同时 $c/p$ 和 $d/p$尽量小, 更可能满足条件

 1 #include<cstdio>
 2 #include<cstring>
 3 #include<algorithm>
 4 #define rd read()
 5 #define R register
 6 using namespace std;
 7 
 8 inline int read() {
 9     int X = 0, p = 1; char c = getchar();
10     for (; c > '9' || c < '0'; c =  getchar())
11         if (c == '-') p = -1;
12     for (; c >= '0' && c <= '9'; c = getchar())
13         X = X * 10 + c - '0';
14     return X * p;
15 }
16 
17 inline void cmax(int &A, int B) {
18     if (A < B) A = B;
19 }
20 
21 inline int cmin(int A, int B) {
22     return A > B ? B : A;
23 }
24 
25 void work() {
26     int ans = 1;
27     int a = rd - 1, b = rd, c = rd - 1, d = rd;
28     for (R int i = 1, j = 1, up = cmin(b, d); i <= up; i = j + 1) {
29         j = cmin(b / (b / i), d / (d / i));
30         if (b / j > a / j && d / j > c / j) cmax(ans, j);
31     }
32     printf("%d\n", ans);
33 }
34 
35 int main()
36 {
37     int n = rd;
38     for (; n; --n) work(); 
39 }
View Code

猜你喜欢

转载自www.cnblogs.com/cychester/p/9866497.html