题目链接:https://ac.nowcoder.com/acm/contest/888/A
解题思路:
将问题转化为计算一个点作为极大全1矩阵的右下角的次数的和。
那么可想而知当一个点(i,j)作为右下角时用(i,k)做左下角比(i,q)时的宽要大(j>k>q),如果是小的话,也不会是极大了。所以当(i,j)作为右下角时,他的多个极大值越往左长越大,宽越小。因此我们就需要用一个单调的东西来维护这个东西。
另外一个问题是枚举右下角时还没考虑到i+1行的情况,所以有可能宽可以再往下延伸,这时候还要记录i+1行不连续的1的位置
#include<bits/stdc++.h>
using namespace std;
typedef pair<int, int> P;
const int mx = 3005;
char a[mx][mx];
int n, m, ans, dp[mx][mx];
int main()
{
cin >> n >> m;
for(int i=1; i<=n; i++) {
scanf("%s", a[i]+1);
for(int j=1; j<=m; j++)
if(a[i][j] == '1')
dp[i][j] = dp[i-1][j]+1;
}
for(int i=1; i<=n; i++){
stack<P>s; int now = -1, pos;
for(int j=1; j<=m+1; j++){
pos = j;
while(!s.empty() && dp[i][j] < s.top().first){
if(s.top().second <= now) ans ++;
pos = s.top().second;
s.pop();
}
if(!dp[i+1][j]) now = j;
if(dp[i][j] && (s.empty() || dp[i][j] > s.top().first))
s.push(P(dp[i][j], pos));
}
}
cout << ans << endl;
}