洛谷P3474 KUP-Plot purchase

简要题意:

给你一个n * n的非负矩阵,求问是否有子矩阵满足和在[k, 2k]之间。若有输出方案。n<=2000。

解:

首先n4暴力很好想(废话),然后发现可以优化成n3log2n,但是还是过不了.....

正解十分之玄妙.....

首先所有大于2k的都不可用。

然后若有一个子矩阵的和不小于k,那么一定有解,且解是这个矩阵的一个子矩阵。

证:

当这个矩阵的和大于2k时,切这个矩阵。

一定有一块大于k。

然后就这样了......

具体实现就看代码了。

  1 #include <cstdio>
  2 #include <algorithm>
  3 
  4 typedef long long LL;
  5 const int N = 2010;
  6 const LL INF = (1ll << 63) - 1;
  7 
  8 LL G[N][N], sum[N][N];
  9 int h[N][N], l[N], r[N], p[N], top;
 10 
 11 inline LL getsum(int left, int right, int u, int d) {
 12     return sum[d][right] - sum[d][left - 1] - sum[u - 1][right] + sum[u - 1][left - 1];
 13 }
 14 
 15 int main() {
 16 
 17     int n, m;
 18     LL k;
 19     scanf("%lld%d", &k, &n);
 20     m = n;
 21     for(int i = 1; i <= n; i++) {
 22         for(int j = 1; j <= m; j++) {
 23             scanf("%lld", &G[i][j]);
 24             sum[i][j] = sum[i][j - 1] + sum[i - 1][j] - sum[i - 1][j - 1] + G[i][j];
 25         }
 26     }
 27     
 28     for(int j = 1; j <= m; j++) {
 29         for(int i = 1; i <= n; i++) {
 30             if(G[i][j] > (k << 1)) {
 31                 h[i][j] = 0;
 32             }
 33             else {
 34                 h[i][j] = h[i - 1][j] + 1;
 35             }
 36             //printf("h %d %d %d \n", i, j, h[i][j]);
 37         }
 38     }
 39     
 40     LL large = -INF;
 41     int u, d, left, right;
 42     
 43     for(int i = 1; i <= n; i++) { // down 
 44         top = 0;
 45         p[0] = 0;
 46         for(int j = 1; j <= m; j++) {
 47             while(top && h[i][p[top]] >= h[i][j]) {
 48                 top--;
 49             }
 50             l[j] = p[top] + 1;
 51             p[++top] = j;
 52         }
 53         top = 0;
 54         p[0] = m + 1;
 55         for(int j = m; j >= 1; j--) {
 56             while(top && h[i][p[top]] >= h[i][j]) {
 57                 top--;
 58             }
 59             r[j] = p[top] - 1;
 60             p[++top] = j;
 61         }
 62         
 63         for(int j = 1; j <= m; j++) {
 64             LL t = getsum(l[j], r[j], i - h[i][j] + 1, i);
 65             if(t > large) {
 66                 large = t;
 67                 u = i - h[i][j] + 1;
 68                 d = i;
 69                 left = l[j];
 70                 right = r[j];
 71             }
 72         }
 73     }
 74     
 75     if(large < k) {
 76         printf("NIE");
 77         return 0;
 78     }
 79     
 80     
 81     while(large > (k << 1)) {
 82         if(u < d) {
 83             int mid = (u + d) >> 1;
 84             if(getsum(left, right, u, mid) >= k) {
 85                 d = mid;
 86             }
 87             else {
 88                 u = mid + 1;
 89             }
 90         }
 91         else {
 92             int mid = (left + right) >> 1;
 93             if(getsum(left, mid, u, d) >= k) {
 94                 right = mid;
 95             }
 96             else {
 97                 left = mid + 1;
 98             }
 99         }
100         large = getsum(left, right, u, d);
101     }
102     
103     printf("%d %d %d %d", left, u, right, d);
104     
105     return 0;
106 }
AC代码

猜你喜欢

转载自www.cnblogs.com/huyufeifei/p/9812561.html