SPOJ MINSUB

http://www.spoj.com/problems/MINSUB/en/

题意:给出一个n*m的矩阵M,和一个面积k,要使得M的子矩阵M'的最小元素最大并且面积大于等于k,问子矩阵M'的最小元素最大能是多少,并且求出最大的面积。

思路:二分一个最小元素x,转化为判断矩阵M里面是否存在一个子矩阵使得这个子矩阵的面积大于等于k并且所有元素都大于x。

用另一个矩阵,1表示该位置的元素大于等于x,0表示元素小于x。

转化为判断是否存在一个子矩阵元素为1的面积大于等于k。

这样可以用到早上学习的单调栈,去维护最大的子矩阵面积。

像这样,求出最大的矩阵面积。

如果矩阵面积大于等于k,那么就去找是否有更大的x去满足题意。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define N 1010
 4 struct node {
 5     int pre, suf, val;
 6 } p[N];
 7 int mat[N][N], mp[N][N], h[N][N], n, m, k, square;
 8 
 9 bool check(int x) {
10     memset(mp, 0, sizeof(mp));
11     memset(h, 0, sizeof(h));
12     for(int i = 1; i <= n; i++)
13         for(int j = 1; j <= m; j++) if(mat[i][j] >= x) mp[i][j] = 1;
14     square = 0;
15     for(int i = 1; i <= n; i++) {
16         stack<node> sta;
17         for(int j = 1; j <= m; j++) {
18             if(mp[i][j]) h[i][j] = h[i-1][j] + 1;
19             p[j] = (node) {1, 1, h[i][j]};
20         }
21         sta.push(p[1]);
22         for(int j = 2; j <= m; j++) {
23             while(!sta.empty() && sta.top().val > p[j].val) {
24                 node top = sta.top(); sta.pop();
25                 if(!sta.empty()) sta.top().suf += top.suf;
26                 p[j].pre += top.pre;
27                 square = max(square, (top.suf + top.pre - 1) * top.val);
28             }
29             sta.push(p[j]);
30         }
31         while(!sta.empty()) {
32             node top = sta.top(); sta.pop();
33             if(!sta.empty()) sta.top().suf += top.suf;
34             square = max(square, (top.suf + top.pre - 1) * top.val);
35         }
36     }
37     if(square >= k) return true;
38     return false;
39 }
40 
41 void solve() {
42     int t;
43     scanf("%d", &t);
44     while(t--) {
45         scanf("%d%d%d", &n, &m, &k);
46         int r = 0, l = 1000000000, ans;
47         for(int i = 1; i <= n; i++) {
48             for(int j = 1; j <= m; j++) {
49                 scanf("%lld", &mat[i][j]);
50                 if(mat[i][j] < l) l = mat[i][j];
51                 if(mat[i][j] > r) r = mat[i][j];
52             }
53         }
54         ans = l;
55         while(l <= r) {
56             int mid = (l + r) >> 1;
57             if(check(mid)) l = mid + 1, ans = mid;
58             else r = mid - 1;
59         }
60         check(ans);
61         printf("%d %d
", ans, square);
62     }
63 }
64 
65 int main() {
66     solve();
67     return 0;
68 }
原文地址:https://www.cnblogs.com/fightfordream/p/6502026.html