SPOJ-MINSUB - Largest Submatrix(单调栈,二分,好题)

来源:互联网 发布:淘宝店铺的升级专业版 编辑:程序博客网 时间:2024/06/05 20:03

题目链接

MINSUB - Largest Submatrix

no tags 

You are given an matrix M (consisting of nonnegative integers) and an integer K.  For any submatrix of M' of M define min(M') to be the minimum value of all the entries of M'.  Now your task is simple:  find the maximum value of min(M') where M' is a submatrix of M of area at least K (where the area of a submatrix is equal to the number of rows times the number of columns it has).

Input

The first line contains a single integer T (T ≤ 10) denoting the number of test cases, T test cases follow.  Each test case starts with a line containing three integers, R (R ≤ 1000), C (C ≤ 1000) and K (K ≤ R * C) which represent the number of rows, columns of the matrix and the parameter K.  Then follow R lines each containing C nonnegative integers, representing the elements of the matrix M.  Each element of M is ≤ 10^9

Output

For each test case output two integers:  the maximum value of min(M'), where M' is a submatrix of M of area at least K, and the maximum area of a submatrix which attains the maximum value of min(M').  Output a single space between the two integers.

Example

Input:22 2 21 11 13 3 21 2 34 5 67 8 9Output:1 48 2
 Submit solution!


题意:

给定一个由非负数组成的矩阵M,和一个整数K,对于矩阵M的子矩阵M’,定义min(M’)M'矩阵中元素的最小值。

我们需要找出这样一个子矩阵,该矩阵的面积至少为K,且min(M’)最大化。面积的定义为该矩阵的行数*列数。求出min(M'),并给出使得min(M')为该值时面积的最大值。


题解:

这类问题都是可以二分答案的。把小于二分值的位置设为0,其他设为1,那么问题就变成了求全为1的子矩阵的最大面积,这件事情可以用单调栈搞(方法类似于http://www.cnblogs.com/ziyi--caolu/archive/2013/06/23/3151556.html ,事先统计出每个位置向左有多少个1)。可以预处理出每个点(i,j)的左边有多少个连续的1(记为f[i][j]),然后枚举每一列,那么这一列就可以类似与单调栈一样处理算出能上下延伸多少,做法和一位数组的单调栈一样。

#include<iostream>#include<cstdio>#include<algorithm>#include<cstring>#include<vector>#include<queue>#include<stack>using namespace std;#define rep(i,a,n) for (int i=a;i<n;i++)#define per(i,a,n) for (int i=n-1;i>=a;i--)#define pb push_back#define fi first#define se secondtypedef vector<int> VI;typedef long long ll;typedef pair<int,int> PII;const int inf=0x3fffffff;const ll mod=1000000007;const int maxn=1000+100;int r,c,k;int a[maxn][maxn];struct node{    int pre,next,v;    node(int a):v(a),pre(1),next(1) {}};stack<node> s;int f[maxn][maxn];int cal(int x){    int ans=0;    while(!s.empty()) s.pop();    memset(f,0,sizeof(f));    rep(i,1,r+1) rep(j,1,c+1)    {        if(a[i][j]>=x) f[i][j]=f[i][j-1]+1;        else f[i][j]=0;    }    rep(j,1,c+1)    {        s.push(node(f[1][j]));        rep(i,2,r+1)        {            node t=node(f[i][j]);            while(!s.empty()&&s.top().v>=t.v)  //此处>或>=都可以            {                node tt=s.top();                s.pop();                t.pre+=tt.pre;                if(!s.empty()) s.top().next+=tt.next;                ans=max(ans,tt.v*(tt.next+tt.pre-1));            }            s.push(t);        }        while(!s.empty())        {            node tt=s.top();            s.pop();            if(!s.empty()) s.top().next+=tt.next;            ans=max(ans,tt.v*(tt.next+tt.pre-1));        }    }    return ans;}int main(){    int cas;    scanf("%d",&cas);    while(cas--)    {        scanf("%d%d%d",&r,&c,&k);        int mi=inf,mx=-inf;        rep(i,1,r+1) rep(j,1,c+1) scanf("%d",&a[i][j]),mi=min(mi,a[i][j]),mx=max(mx,a[i][j]);        int l=mi,r=mx,ans=0;        while(l<=r)        {            int mid=(l+r)/2;            if(cal(mid)>=k) l=mid+1,ans=mid;            else r=mid-1;        }        printf("%d %d\n",ans,cal(ans));    }    return 0;}

0 0