国际象棋是世界上最古老的博弈游戏之一,和中国的围棋、象棋以及日本的将棋同享盛名。据说国际象棋起源于易经的思想,棋盘是一个8×8大小的黑白相间的方阵,对应八八六十四卦,黑白对应阴阳。
而我们的主人公小Q
,正是国际象棋的狂热爱好者。作为一个顶尖高手,他已不满足于普通的棋盘与规则,于是他跟他的好朋友小W
决定将棋盘扩大以适应他们的新规则。
小Q
找到了一张由N×M个正方形的格子组成的矩形纸片,每个格子被涂有黑白两种颜色之一。小Q想在这种纸中裁减一部分作为新棋盘,当然,他希望这个棋盘尽可能的大。
不过小Q还没有决定是找一个正方形的棋盘还是一个矩形的棋盘(当然,不管哪种,棋盘必须都黑白相间,即相邻的格子不同色),所以他希望可以找到最大的正方形棋盘面积和最大的矩形棋盘面积,从而决定哪个更好一些。
于是小Q
找到了即将参加全国信息学竞赛的你,你能帮助他么?
包含两个整数N和M,分别表示矩形纸片的长和宽。接下来的NNN行包含一个N ×M的01矩阵,表示这张矩形纸片的颜色(0表示白色,1表示黑色)。
包含两行,每行包含一个整数。第一行为可以找到的最大正方形棋盘的面积,第二行为可以找到的最大矩形棋盘的面积(注意正方形和矩形是可以相交或者包含的)。
输入 #1
3 3 1 0 1 0 1 0 1 0 0
输出 #1
4 6
对于20%20\%20%的数据,N,M≤80N, M ≤ 80N,M≤80
对于40%40\%40%的数据,N,M≤400N, M ≤ 400N,M≤400
对于100%100\%100%的数据,N,M≤2000N, M ≤ 2000N,M≤2000
开题考虑如何处理01相间的问题,对此采用xor,对当前给出矩阵,假设存在一个大小相同的棋盘,将二者亦或之后得到结果仍为01矩阵,但题目将转化为求连续的0矩阵或1矩阵(对于没有做过“P4147玉蟾宫”的人来说想到这步就挺可的)。
对接下来的连续0/1阵,用单调栈。
预处理p[i][j]表示(i,j)位置向上的相邻的相同的格子有多少个,对每一行进行单调栈维护单调不下降序列,在弹出时计算宽度(第二维j的跨度),高度(p[i][j]的值)构成的矩形面积,正方形面积判断宽高相等。
1.每行最后多加入高度为0的数使栈中元素全部参与计算
2.因为维护的是单调不下降序列,计算宽度时不应采用栈顶元素j值,而应为栈内栈顶下方元素j值,因为即使前方较高矩形被弹出,其宽度也应连续延续到之前的位置。(请理解我给出的如下样例)
5 5
0 1 0 0 1
1 0 1 1 0
0 1 0 1 0
0 0 1 0 1
0 1 0 1 0
输出为 9 12
#include
#include
#include
#include
#include
using namespace std;
const int Maxn = 2000 + 5;
const int Maxm = 10;
int N, M, ans1, ans2;
pairstk[Maxn];
int mp[Maxn][Maxn], p[Maxn][Maxn];
void getint(int &num){
char c; int flg = 1; num = 0;
while((c = getchar()) < '0' || c > '9')if(c == '-') flg = -1;
while(c >= '0' && c <= '9'){num = num * 10 + c - 48; c = getchar();}
num *= flg;
}
void solve(bool tg){
for(int j = 1; j <= M; ++ j) p[1][j] = mp[1][j] == tg;
for(int i = 2; i <= N; ++ i)
for(int j = 1; j <= M; ++ j){
if(mp[i][j] == tg && mp[i][j] == mp[i-1][j])
p[i][j] = p[i-1][j]+1;
else p[i][j] = mp[i][j] == tg;
}
/*puts("****************************");
for(int i = 1; i <= N; ++ i){
for(int j = 1; j <= M; ++ j)
printf("%d ", p[i][j]);
puts("");
}*/
int mm = M+1;
for(int i = 1; i <= N; ++ i){
int tp = 0;
for(int j = 1; j <= mm; ++ j){
while(tp && p[i][j] < stk[tp].first){
if(stk[tp].first == j-1-stk[tp-1].second)
ans1 = max(ans1, stk[tp].first*(j-1-stk[tp-1].second));
ans2 = max(ans2, stk[tp].first*(j-1-stk[tp-1].second));
-- tp;
}
if(p[i][j] >= stk[tp].first)
stk[++tp] = make_pair(p[i][j], j);
}
}
}
int main(){
getint(N), getint(M);
for(int i = 1; i <= N; ++ i)
for(int j = 1; j <= M; ++ j){
getint(mp[i][j]);
if((i+j)&1)
mp[i][j] = (mp[i][j]&1);
else mp[i][j] = (mp[i][j]==0);
}
/*puts("****************************");
for(int i = 1; i <= N; ++ i){
for(int j = 1; j <= M; ++ j)
printf("%d ", mp[i][j]);
puts("");
}*/
solve(1);
solve(0);
printf("%d\n%d\n", ans1, ans2);
return 0;
}