ICPC Latin American Regional Contests 2019 L Leverage MDT 【单调栈】

Description

The kingdom of Nlogonia is a very prosperous one. Its king, Constan tourist, expanded the kingdom by conquering nearby towns. However, now that Constantourist’s life is coming to an end, his two sons, Javasar and Golangsar, need to decide the fate of the kingdom.

Instead of fighting an unnecessary war to choose the next king, the two sons are trying to negotiate an agreement so as to divide the kingdom’s jurisdiction into two. Nlogonia is are ctangle-shaped land having N kilometers in the North-South direction and M kilometers in the West-East direction. Thus, during the initial stage of negotiations the two sons were able to divide the land in N × M square parcels of one kilometer on each side, using divisory lines parallel to the kingdom’s border. The next step is to distribute the parcels between the two sons.

Before the negotiations can continue, Javasar needs to decide which parcels he wants to claim for himself. He has already categorized each parcel in either good or bad, according to soil quality. Javasar wants his jurisdiction to be recognized as the best in Nlogonia, and so he is planning to choose only parcels with good soil quality. Moreover, being a perfectionist, he decided that the parcels that he will claim need to form a square.

Javasar is worried that these requirements might make him get only a few amount of parcels.Luckily for him, during one of his adventures to Byteland, he found an ancient Magical DivineTool (MDT) which, when active, is able to reverse the soil quality of the parcel Javasar is currently standing in. In other words, if active, the MDT turns a bad quality parcel into a good one, and vice versa.

With this handy tool, Javasar came up with the perfect plan! He will travel outside the kingdom, to the West of the parcel that is at the North-West corner, and then he will visit each parcel exactly once following the route that the picture below shows. Notice that Javasar will enter and leave Nlogonia several times. In this way he will avoid activating or deactivating the MDT when he is inside the kingdom, and then nobody will see him manipulating the tool.Although the MDT is magical and divine, it does not activate or deactivate by itself.

图片.png

As Javasar's main advisor, you must tell him the maximum number of parcels it is possible to obtain, meeting his requirements, if he optimally leverages the MDT.

Input

The first line contains two integers N and M (1 ≤ N, M ≤ 1000), indicating the length (inkilometers) of Nlogonia in the North-South and West-East directions, respectively. Each of the next N lines contains a string of M characters, where each character is either the uppercase letter “G” or the uppercase letter “B”, representing that the soil quality of a parcel is good or bad, respectively. The description of the kingdom’s parcels is made from North to South, and from West to East. 

Output

Output a single line with an integer indicating the maximum number of parcels Javasar can obtain, whilst meeting his requirements, if he optimally leverages the MDT. 

样例输入1

2 2
GG
GG

样例输出1

4

 样例输入2

5 5
GGGGG
GBBBG
GBBBG
GBBBG
GGGGG

 样例输出2

9

题目大意:

给定一个n*m的01矩阵,矩阵的每一行可以取反,也可以保持不变,求在这个条件下能获得的最大全1正方形子矩阵。

分析:

首先,最终的子矩阵一定为全1,但是由于每一行可以选择取反与否,那么如果我们将结果退回到没有对任何一行取反的情况,则对这个子矩阵的限制实际上就转化为:它的每一行要么全为0,要么全为1。行与行之间的状态是相互独立的。

那么问题就转化为,要找到一个最大的子矩阵,满足它的每一行要么全为0,要么全为1,即相同行的所有元素状态相同,不同行 的元素之间没有影响。

所以我们定义 lft[i][j] ,表示从 (i,j) 向左与当前位置状态相同的最大长度。

然后按列遍历,对于每一列:

利用单调栈,求出 up[i][j] ,表示以 lft[i][j] 为子矩阵的一边,向上能拓展到达的最远处。

同理,反方向利用单调栈,求出 dwn[i][j] ,表示以 lft[i][j] 为子矩阵的一边,向下能拓展到达的最远处。

那么在 (i,j) 这个位置能获得的极大正方形子矩阵的边长就是 min( lft[i][j] , dwn[i][j] - up[i][j] + 1 ) 。

具体解释见代码。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <string>
#include <cmath>
#include <vector>
#include <map>
#include <set>
#include <queue>
#define INF 0x3f3f3f3f
#define mst(a,num) memset(a,num,sizeof a)
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define repd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
typedef long long ll;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
const ll mod = 1e9 + 7;
const int maxn = 2000 + 5;

char mp[maxn][maxn];
int lft[maxn][maxn];
int up[maxn][maxn],dwn[maxn][maxn];
vector<int> sta;                    //单调栈

int main() {
    int n,m;
    scanf("%d%d",&n,&m);
    rep(i,1,n){
        scanf("%s",mp[i]+1);
        rep(j,1,m){
            lft[i][j]=1;            //初始化可拓展的长度为1
            up[i][j]=dwn[i][j]=i;   //初始化最远可到达的行为当前行
        }
    }
    rep(i,1,n){
        rep(j,2,m){
            if(mp[i][j]==mp[i][j-1])  lft[i][j]=lft[i][j-1]+1;  //利用左边一个位置的lft更新当前位置的lft
        }
    }
    int ans=0;
    rep(j,1,m){                 //按列遍历
        sta.clear();
        sta.push_back(0);       //预先压入第0行的高度(为0),保证栈不会空
        rep(i,1,n){             //正着扫一遍单调栈
            int tp=sta.back();
            if(lft[i][j]>lft[tp][j]){
                sta.push_back(i);
            }
            else{
                while(!sta.empty()&&lft[sta.back()][j]>=lft[i][j]){
                    sta.pop_back();
                }
                up[i][j]=sta.back()+1;
                sta.push_back(i);
            }
        }
        sta.clear();
        sta.push_back(n+1);     //预先压入第n+1行的高度(为0),保证栈不会空
        repd(i,n,1){            //反着扫一遍单调栈
            int tp=sta.back();
            if(lft[i][j]>lft[tp][j]){
                sta.push_back(i);
            }
            else{
                while(!sta.empty()&&lft[sta.back()][j]>=lft[i][j]){
                    sta.pop_back();
                }
                dwn[i][j]=sta.back()-1;
                sta.push_back(i);
            }
        }
        rep(i,1,n){
            ans=max(ans,min(lft[i][j],dwn[i][j]-up[i][j]+1));
        }
    }
    printf("%d\n",ans*ans);
    return 0;
}
发布了30 篇原创文章 · 获赞 5 · 访问量 900

猜你喜欢

转载自blog.csdn.net/qq_42840665/article/details/105444158