BZOJ 3039 玉蟾宫
Description
有一天,小猫rainbow和freda来到了湘西张家界的天门山玉蟾宫,玉蟾宫宫主蓝兔盛情地款待了它们,并赐予它们一片土地。
这片土地被分成N*M个格子,每个格子里写着'R'或者'F',R代表这块土地被赐予了rainbow,F代表这块土地被赐予了freda。
现在freda要在这里卖萌。。。它要找一块矩形土地,要求这片土地都标着'F'并且面积最大。
但是rainbow和freda的OI水平都弱爆了,找不出这块土地,而蓝兔也想看freda卖萌(她显然是不会编程的……),所以它们决定,如果你找到的土地面积为S,它们每人给你S两银子。
Input
第一行两个整数N,M,表示矩形土地有N行M列。
接下来N行,每行M个用空格隔开的字符'F'或'R',描述了矩形土地。
Output
输出一个整数,表示你能得到多少银子,即(3*最大'F'矩形土地面积)的值。
Sample Input
5 6
R F F F F F
F F F F F F
R R R F F F
F F F F F F
F F F F F F
R F F F F F
F F F F F F
R R R F F F
F F F F F F
F F F F F F
Sample Output
45
HINT
对于50%的数据,1<=N,M<=200
对于100%的数据,1<=N,M<=1000
题意:给你一个0 1的矩阵,求最大的全是1的矩阵。
题解:枚举矩形下方的两个点(这个过程只需要枚举3个坐标),然后再找最大能够向上延伸多高。容易预处理出每个位置向上最多延伸多高,那么要求的就是这两个点直接所有点(包括这两个点)的延伸高度的最小值。
对于区间最小值作贡献问题,一个常用的套路是枚举最小值,考虑贡献。那么可以使用单调栈(查询向左和向右第一个小于它的高度的值,向左向右维护一个单调递增的栈即可)处理出一个数左边第一个小于它的位置和右边第一个小于它的位置。这两个位置之间的都大于它,此时这个数作为最小值,最大宽度为位置差,直接计算贡献即可。O(n*m)
暴力(n^3) 不能过的
View Code
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include <bits/stdc++.h> const int maxn=1005; int n, m, a[maxn][maxn]; int main() { char s[10]; scanf("%d%d", &n, &m); for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) { scanf("%s", s); a[i][j]= s[0]=='F'? 1+a[i][j-1]:a[i][j-1]; } int ans=0; for(int l=1; l<=m; l++) for(int r=l; r<=m; r++) { int tans=0; for(int i=1; i<=n; i++) { if(a[i][r]-a[i][l-1]==r-l+1) tans+=a[i][r]-a[i][l-1]; else tans=0; ans=std::max(ans, tans); } } printf("%d\n", ans*3); return 0; }
单调栈:
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
/************************************************************** Problem: 3039 User: strangers Language: C++ Result: Accepted Time:780 ms Memory:5244 kb ****************************************************************/ #include <bits/stdc++.h> const int maxn=1005; int n, m, a[maxn][maxn]; int ls[maxn], rs[maxn], stk[maxn], top; void debug() { for(int i=1; i<=m; i++) printf("ls[%d]=%d, rs[%d]=%d ", i, ls[i], i, rs[i]); printf("\n"); } int main() { char s[10]; scanf("%d%d", &n, &m); for(int i=1; i<=n; i++) for(int j=1; j<=m; j++) { scanf("%s", s); a[i][j]= s[0]=='F'? 1+a[i-1][j]:0; } int ans=0; for(int i=1; i<=n; i++) { top=0, stk[top]=0; for(int j=1; j<=m; j++) { while(top && a[i][stk[top]]>=a[i][j]) top--; ls[j]=stk[top], stk[++top]=j; } top=0, stk[top]=m+1; for(int j=m; j; j--) { while(top && a[i][stk[top]]>=a[i][j]) top--; rs[j]=stk[top], stk[++top]=j; } //debug(); for(int j=1; j<=m; j++) ans=std::max(ans, a[i][j]*(rs[j]-ls[j]-1)); } printf("%d\n", ans*3); return 0; }