【题目链接】点击打开链接

【题意】 是说给定一个R*C的非负矩阵,试求出一个包含数字数>=K的子矩阵,使得这个子矩阵中最小的数字最大.
【解题思路】

             主要是二分答案,即二分那个最小的数字,然后针对每次二分的值mid,可以将原矩阵根据是否满足A[i][j]>=mid,而转成一个R*C的01矩阵a[][],然后问题求变成了给定一个二维01矩阵,求最大的满1矩阵,可以用单调栈的思想来处理这个子问题,设b[i][j]表示从a[i][j]的位置(包含)向上最多有几个连续的1存在
  比如 1 1 0
         1 0 1
的b[][]={{1,1,0},{2,0,1}}
然后对于每个i单独处理第i行(即子矩阵是以第i行为下边界的情况),设L[i][j]表示从j开始向左满足b[i][k]>=b[i][j]条件所能延伸到的最大的位置,而R[i][j]类似表示相应能够到的最右的位置
比如    j=1 2 3 4 5 6
  b[][j]=4 1 3 2 5 6
则lef[][]=1 1 3 3 5 6
 rig[][]=1 6 3 6 6 6

然后求lef[][]和rig[][]的过程对于每行可以运用单调栈在O(n)时限内完成。

SB的把单调栈写错了,竟然还过了样例。。


//
//Created by just_sort 2016/1/5
//Copyright (c) 2016 just_sort.All Rights Reserved
//

//#include <ext/pb_ds/assoc_container.hpp>
//#include <ext/pb_ds/tree_policy.hpp>
//#include <ext/pb_ds/hash_policy.hpp>
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdio>
#include <time.h>
#include <cstdlib>
#include <cstring>
#include <sstream> //isstringstream
#include <iostream>
#include <algorithm>
using namespace std;
//using namespace __gnu_pbds;
typedef long long LL;
typedef pair<int, LL> pp;
#define REP1(i, a, b) for(int i = a; i < b; i++)
#define REP2(i, a, b) for(int i = a; i <= b; i++)
#define REP3(i, a, b) for(int i = a; i >= b; i--)
#define CLR(a, b)     memset(a, b, sizeof(a))
#define MP(x, y)      make_pair(x,y)
const int maxn = 2010;
const int maxm = 2e5;
const int maxs = 10;
const int maxp = 1e3 + 10;
const int INF  = 1e9;
const int UNF  = -1e9;
const int mod  = 1e9 + 7;
int gcd(int x, int y) {return y == 0 ? x : gcd(y, x % y);}
//typedef tree<int,null_type,less<int>,rb_tree_tag,tree_order_statistics_node_update>order_set;
//head
int getmax(int x, int y)
{
    return x > y ? x : y;
}
int a[maxn][maxn], b[maxn][maxn], L[maxn][maxn], R[maxn][maxn], st[maxn];
int n, m, k, top;

int check(int x)
{
    int ans = 0;
    REP2(j, 1, m) b[1][j] = (a[1][j] >= x);
    REP2(i, 2, n){
        REP2(j, 1, m){
            b[i][j] = (a[i][j] >= x) ? (b[i - 1][j] + 1) : 0;
        }
    }
    REP2(i, 1, n){
        top = st[1] = L[i][1] = 1;
        REP2(j, 2, m){
            while(top > 0 && b[i][st[top]] >= b[i][j]) top--;
            L[i][j] = (top) ? (st[top] + 1) : 1; st[++top] = j;
        }
        top = 1;
        st[1] = R[i][m] = m;
        REP3(j, m - 1, 1){
            while(top > 0 && b[i][st[top]] >= b[i][j]) top--;
            R[i][j] = (top) ? (st[top] - 1) : m; st[++top] = j;
        }
        REP2(j, 1, m) if(b[i][j]) ans = getmax(ans, b[i][j] * (R[i][j] - L[i][j] + 1));
    }
    return ans;
}

int main()
{
    int T;
    scanf("%d", &T);
    while(T--){
        scanf("%d%d%d", &n, &m, &k);
        REP2(i, 1, n){
            REP2(j, 1, m){
                scanf("%d", &a[i][j]);
            }
        }
        int l = 0, r = 1e9;
//        while(l + 1 < r){
//            int mid = (l + r) >> 1;
//            if(check(mid) >= k) l = mid;
//            else r = mid - 1;
//        }
//        if(check(r) >= k) l = r;
//        while(l < r){
//            int mid = (l + r) / 2;
//            if(check(mid) >= k) l = mid + 1;
//            else r = mid - 1;
//        }
//        if(check(r) >= k) l = r;
        while(l < r){
            int mid = (l + r) / 2;
            if(check(mid) >= k) l = mid + 1;
            else r = mid;
        }
        printf("%d %d\n", l - 1, check(l - 1));
    }
    return 0;
}