poj3179 Corral the Cows

论水题与难题的差距:在于一个upper_bound

那么,这题一看就很显然了:因为答案满足二分性质所以我们二分。

然后我们再建造一个二维前缀和,每次判断的时候怎么办呢?

我先以为是贪心:选择以每个点为角落的正方形。后来瞬间构造反例:


  —————

丨    ·     丨

丨        · 丨

丨·         丨

丨     ·    丨

  —————


然后考虑枚举:500 * 500, 随便水!

然后狂T不止...

发现在枚举内部我还有枚举,具体来说时间复杂度是:log10000 * 500 * 500 * 500

然后我改用了upper_bound,时间复杂度变为:log10000 * 500 * 500 * log500

然后果然A了!

 1 /// poj3179
 2 #include <cstdio>
 3 #include <algorithm>
 4 #include <iostream>
 5 using namespace std;
 6 const int N = 510;
 7 
 8 int a[N], b[N], x[N], y[N], g[N][N], sum[N][N], n, C, tx, ty;
 9 
10 inline bool check(int k) {
11     //printf("check:%d
", k);
12     int ans = 0;
13     for(int i = 1; i <= tx; i++) {
14         for(int j = 1; j <= ty; j++) {
15             int ii = upper_bound(x + i, x + tx + 1, x[i] + k) - x - 1;
16             int jj = upper_bound(y + j, y + ty + 1, y[j] + k) - y - 1;
17             /// 就是这里!
18             //printf("%d %d %d %d ", i, j, ii, jj);
19             ans = max(ans, sum[ii][jj] - sum[ii][j - 1] - sum[i - 1][jj] + sum[i - 1][j - 1]);
20             if(ans >= C) return 1;
21             //printf("ans=%d
", ans);
22             //ii = i; jj = j;
23             //while(ii >= 0 && x[ii] - x[i] )
24         }
25     }
26     //printf("%d
", ans);
27     return ans >= C;
28 }
29 
30 int main() {
31     int m = -1;
32     scanf("%d%d", &C, &n);
33     for(int i = 1; i <= n; i++) {
34         scanf("%d%d", &a[i], &b[i]);
35         x[i] = a[i];
36         y[i] = b[i];
37         m = max(m, x[i]);
38         m = max(m, y[i]);
39     }
40     sort(x + 1, x + n + 1);
41     sort(y + 1, y + n + 1);
42     for(int i = 1; i <= n; i++) {
43         if(x[i] != x[i - 1]) {
44             x[++tx] = x[i];
45         }
46         if(y[i] != y[i - 1]) {
47             y[++ty] = y[i];
48         }
49     }
50     for(int i = 1; i <= n; i++) {
51         int px = lower_bound(x + 1, x + tx + 1, a[i]) - x;
52         int py = lower_bound(y + 1, y + ty + 1, b[i]) - y;
53         g[px][py]++;
54     }
55     for(int i = 1; i <= tx; i++) {
56         for(int j = 1; j <= ty; j++) {
57             sum[i][j] = sum[i - 1][j] + sum[i][j - 1] - sum[i - 1][j - 1] + g[i][j];
58         }
59     }
60     int l = 0, r = m, mid;
61     while(l < r) {
62         mid = (l + r) >> 1;
63         if(check(mid)) {
64             r = mid;
65         }
66         else l = mid + 1;
67     }
68     printf("%d", r + 1);
69     return 0;
70 }
AC代码

小细节:1 * 1的方框边长是0,n * n的方框边长是n - 1

所以我最后输出时 + 1

原文地址:https://www.cnblogs.com/huyufeifei/p/9031815.html