Description

国际象棋是世界上最古老的博弈游戏之一, 和中国的围棋、象棋以及日本的将棋同享盛名. 据说国际象棋起源于易经的思想, 棋盘是一个 \(8 \times 8\) 大小的黑白相间的方阵, 对应 八八六十四卦, 黑白对应阴阳. 而我们的主人公小 Q, 正是国际象棋的狂热爱好者. 作为 一个顶尖高手, 他已不满足于普通的棋盘与规则, 于是他跟他的好朋友小 W 决定将棋盘扩大以适应他们的新规则. 小 Q 找到了一张由 \(n \times m\) 个正方形的格子组成的矩形纸片, 每个格子被涂有黑白两种颜色之一. 小 Q 想在这种纸中裁减一部分作为新棋盘, 当然, 他希望这个棋盘尽可能的大. 不过小 Q 还没有决定是找一个正方形的棋盘还是一个矩形的棋盘 (当然, 不管哪种, 棋盘必须都黑白相间, 即相邻的格子不同色), 所以他希望可以找到最大的正方形棋盘面积和最大的矩形棋盘面积, 从而决定哪个更好一些. 于是小 Q 找到了即将参加全国信息学竞赛的你, 你能帮助他么?

Input

第一行包含两个整数 \(n\)\(m\), 分别表示矩形纸片的长和宽. 接下来的 \(n\) 行包含一个 \(n \times m\) 的 0-1 矩阵, 表示这张矩形纸片的颜色 (0 表示白色, 1 表示黑色).

Output

包含两行, 每行包含一个整数. 第一行为可以找到的最大正方形棋盘的面积, 第二行为可以 找到的最大矩形棋盘的面积 (注意正方形和矩形是可以相交或者包含的).

Sample Input

3 3
1 0 1
0 1 0
1 0 0

Sample Output

4
6

Data Range

对于所有的数据, 满足 \(n, m \leq 2000\)

Explanation

黄学长说的是什么悬线法...... 明明就是高维递推......

话说这种方法我都用了多少年了, 现在才知道有这样一个高大上的名称~

但是把它交到 1052 是怎么回事...... 突然间把我吓到了......

Source Code


#include <iostream>
#include <cstdlib>
#include <cstdio>

using namespace std;
typedef long long lli;
const int maxn = 2010;

int n, m;
int arr[maxn][maxn], // Content of matrix unit
    col_csq[maxn][maxn], // Max consequential choice of units in col, until here
    rlef[maxn][maxn], // Leftest reachable position in row
    rrig[maxn][maxn]; // Rightest reachable position in row
int res_sqr, res_rect;

int main(int argc, char** argv)
{
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++) {
            scanf("%d", &arr[i][j]);
            if (i == 1) col_csq[i][j] = 1;
            else if (arr[i][j] != arr[i - 1][j])
                col_csq[i][j] = col_csq[i - 1][j] + 1;
            else
                col_csq[i][j] = 1;
        }
    // Finished data read-in and row-consequential-choice construction.
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            rlef[i][j] = j;
            while (rlef[i][j] > 1 &&
                    col_csq[i][rlef[i][j] - 1] >= col_csq[i][j] &&
                    arr[i][rlef[i][j] - 1] != arr[i][rlef[i][j]])
                rlef[i][j] = rlef[i][rlef[i][j] - 1];
        }
        for (int j = m; j >= 1; j--) {
            rrig[i][j] = j;
            while (rrig[i][j] < m &&
                    col_csq[i][rrig[i][j] + 1] >= col_csq[i][j] &&
                    arr[i][rrig[i][j] + 1] != arr[i][rrig[i][j]])
                rrig[i][j] = rrig[i][rrig[i][j] + 1];
        }
        // Fetching results
        for (int j = 1; j <= m; j++) {
            int height = rrig[i][j] - rlef[i][j] + 1;
            res_rect = max(res_rect, height * col_csq[i][j]);
            height = min(height, col_csq[i][j]);
            res_sqr = max(res_sqr, height * height);
        }
    }
    printf("%d\n%d\n", res_sqr, res_rect);
    return 0;
}