首页 > 代码库 > spoj MINSUB 单调栈+二分
spoj MINSUB 单调栈+二分
题目链接:点击传送
MINSUB - Largest Submatrix
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
题意:给你一个n*m的矩阵,求以一个最小值为m的最大矩阵面积s需要大于等于K
思路:二分答案,check怎么写呢。。
类似bzoj 3039这题;
利用单调栈,求最大子矩阵面积;
将check的x,大于等于x的值均改成1,求1的最大面积;
枚举每个位置,以该位置能最大的上升的位置为权值;
例如:
1 0 1 1 0 1
1 1 0 --> 2 1 0
1 0 1 3 0 1
利用单调栈查找 以该权值为最大值最多可以往左和往右延伸最大长度;
详见代码
#pragma comment(linker, "/STACK:1024000000,1024000000")#include<iostream>#include<cstdio>#include<cmath>#include<string>#include<queue>#include<algorithm>#include<stack>#include<cstring>#include<vector>#include<list>#include<set>#include<map>using namespace std;#define ll long long#define pi (4*atan(1.0))#define eps 1e-14#define bug(x) cout<<"bug"<<x<<endl;const int N=1e3+10,M=1e6+10,inf=2147483647;const ll INF=1e18+10,mod=1e9+7;int a[N][N],b[N][N];int l[N],r[N],s[N];int dp[N][N];int n,m,k;int check(int x){ for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) b[i][j]=(a[i][j]>=x); memset(dp,0,sizeof(dp)); int ans=0; for(int i=1;i<=n;i++) { for(int j=1;j<=m;j++) if(b[i][j])dp[i][j]=dp[i-1][j]+1; else dp[i][j]=0; dp[i][0]=dp[i][m+1]=-1; int si=0; s[++si]=0; for(int j=1;j<=n;j++) { while(dp[i][s[si]]>=dp[i][j])si--; l[j]=s[si]; s[++si]=j; } si=0; s[++si]=m+1; for(int j=m;j>=1;j--) { while(dp[i][s[si]]>=dp[i][j])si--; r[j]=s[si]; s[++si]=j; } for(int j=1;j<=m;j++) ans=max(ans,(r[j]-l[j]-1)*dp[i][j]); } return ans;}int main(){ int T,cas=1; scanf("%d",&T); while(T--) { scanf("%d%d%d",&n,&m,&k); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) scanf("%d",&a[i][j]); int st=0; int en=1e9+10,ans=-1; while(st<=en) { int mid=(st+en)>>1; if(check(mid)>=k) { ans=mid; st=mid+1; } else en=mid-1; } printf("%d %d\n",ans,check(ans)); } return 0;}
spoj MINSUB 单调栈+二分