鏈接:https://ac.nowcoder.com/acm/contest/882/H
來源:牛客網
題目描述
給出N*M的二維矩陣,每個位置爲0或1,求其中第二大的全爲1的矩陣的面積,不存在輸出0。
輸入
1 2
01
輸出
0
輸入
1 3
101
輸出
1
題目分析:
用O(N*M)的時間處理出每個up[i][j],表示位置(i,j)往上連續的1的數量。
對每一行統計答案貢獻,在每一行中,問題轉換成柱狀圖中的最大矩形問題,白書單調棧經典例題,O(M)可以解決一行,總時間複雜度O(N*M)。
要求的是第二大矩形的面積,只需要在求最大矩形的時候把每個最大矩形刪去一行或刪去一列的1,就能保證次大會被統計到答案中了。
代碼:
#include<bits/stdc++.h>
typedef long long ll;
using namespace std;
const int INF = 0x3f3f3f3f;
const int MAXN = 100005;
int n, m;
char s[1005][1005];
int up[1005][1005];
ll res[2];
void update(ll siz) {
if(siz >= res[0]) {
res[1] = res[0], res[0] = siz;
} else if(siz > res[1])
res[1] = siz;
}
ll L[1005], R[1005];
bool vis[1005][1005];
void getmax(int a[]) {
stack<int> stk;
a[0] = a[m + 1] = 0;
stk.push(0);
for(int i = 1; i <= m; i++) {
while(stk.size() && a[stk.top()] >= a[i])
stk.pop();
if(stk.size())
L[i] = stk.top();
stk.push(i);
}
while(stk.size())
stk.pop();
stk.push(m + 1);
for(int i = m; i >= 1; i--) {
while(stk.size() && a[stk.top()] >= a[i])
stk.pop();
if(stk.size())
R[i] = stk.top();
stk.push(i);
}
typedef pair<int, int> P;
vector<P>v;
for(int i = 1; i <= m; i++) {
ll W = R[i] - L[i] - 1, H = a[i];
if(vis[L[i]][R[i]] || W == 0 || H == 0)
continue;
vis[L[i]][R[i]] = 1; //打標記防止同一個矩形被計入答案多次
update(H * W); //最大
update(H * W - min(H, W)); //次大
v.push_back(P(L[i], R[i]));
}
for(auto &k : v)
vis[k.first][k.second] = 0;
}
int main() {
scanf("%d%d", &n, &m);
for(int i = 1; i <= n; i++)
scanf("%s", s[i] + 1);
for(int j = 1; j <= m; j++) {
up[0][j] = 0;
for(int i = 1; i <= n; i++)
up[i][j] = s[i][j] == '1' ? up[i - 1][j] + 1 : 0;
}
for(int i = 1; i <= n; i++)
getmax(up[i]);
printf("%lld\n", res[1]);
return 0;
}