【Cf #291 B】R2D2 and Droid Army(二分,线段树)

因为题目中要求使连续死亡的机器人最多,令人联想到二分答案。

考虑如何检验这之中是否存在一段连续的长度为md的区间,其中花最多k步使得它们都死亡。

这个条件等价于区间中m个最大值的和不超过k。

枚举起点,可以用 $ O(mlogn) $ 的时间确定这段区间是否合法,最终check的复杂度是 $ O(nmlogn) $。

总复杂度是 $ O(nmlog^{2}n) $。

 

$ \bigodot $ 技巧&套路:

  • 最大(小)值的问题,可以考虑二分答案。
  • check时用线段树优化区间平移,来枚举每一个长度固定的区间。
 1 #include <cstdio>
 2 #include <iostream>
 3 #include <algorithm>
 4 
 5 const int N = 100005;
 6 
 7 int n, m, k, re;
 8 int a[N][6], ans[6], tmp[6];
 9 
10 namespace SE {
11   int ma[6][N << 2];
12   inline void Up(int t) {
13     for (int i = 1; i <= m; ++i) {
14       ma[i][t] = std::max(ma[i][t << 1], ma[i][t << 1 | 1]);
15     }
16   }
17   void Build(int t, int l, int r) {
18     if (l == r) {
19       for (int i = 1; i <= m; ++i) ma[i][t] = a[l][i];
20       return;
21     }
22     int md = (l + r) >> 1;
23     Build(t << 1, l, md);
24     Build(t << 1 | 1, md + 1, r);
25     Up(t);
26   }
27   int Query(int t, int l, int r, int L, int R, int ty) {
28     if (L <= l && r <= R) return ma[ty][t];
29     int md = (l + r) >> 1, re = 0;
30     if (L <= md) re = std::max(re, Query(t << 1, l, md, L, R, ty));
31     if (md < R) re = std::max(re, Query(t << 1 | 1, md + 1, r, L, R, ty));
32     return re;
33   } 
34 }
35 
36 inline int Check(int md) {
37   for (int i = 1; i + md - 1 <= n; ++i) {
38     int sum = 0;
39     for (int j = 1; j <= m; ++j) {
40       tmp[j] = SE::Query(1, 1, n, i, i + md - 1, j);
41       sum += tmp[j];
42       if (sum > k) break;
43     }
44     if (sum <= k) {
45       for (int j = 1; j <= m; ++j) ans[j] = tmp[j];
46       return 1;
47     }
48   }
49   return 0;
50 }
51 
52 int main() {
53   scanf("%d%d%d", &n, &m, &k);
54   for (int i = 1; i <= n; ++i) {
55     for (int j = 1; j <= m; ++j) {
56       scanf("%d", &a[i][j]);
57     }
58   }
59   SE::Build(1, 1, n);
60   for (int nl = 1, nr = n, md; nl <= nr; ) {
61     md = (nl + nr) >> 1;
62     if (Check(md)) {
63       re = md; nl = md + 1;
64     } else {
65       nr = md - 1;
66     }
67   }
68   if (re) Check(re);
69   for (int i = 1; i <= m; ++i) {
70     printf("%d ", (re)? ans[i] : 0);
71   }
72 
73   return 0;
74 }
View Code

 

posted @ 2018-07-11 21:31  Dance_Of_Faith  阅读(265)  评论(0编辑  收藏  举报