2019牛客暑期多校训练营(第八场)A题(单调栈)

题目链接: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
using namespace std;
typedef pair 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

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; }

 

你可能感兴趣的:(DP,单调性)