1. 程式人生 > >bzoj 1057: [ZJOI2007]棋盤製作

bzoj 1057: [ZJOI2007]棋盤製作

我扔

1057: [ZJOI2007]棋盤製作

Time Limit: 20 Sec  Memory Limit: 162 MB
Submit: 3851  Solved: 2009
[Submit][Status][Discuss]

Description

 

  國際象棋是世界上最古老的博弈遊戲之一,和中國的圍棋、象棋以及日本的將棋同享盛名。據說國際象棋起源

於易經的思想,棋盤是一個8*8大小的黑白相間的方陣,對應八八六十四卦,黑白對應陰陽。而我們的主人公小Q,

正是國際象棋的狂熱愛好者。作為一個頂尖高手,他已不滿足於普通的棋盤與規則,於是他跟他的好朋友小W決定

將棋盤擴大以適應他們的新規則。小Q找到了一張由N*M個正方形的格子組成的矩形紙片,每個格子被塗有黑白兩種

顏色之一。小Q想在這種紙中裁減一部分作為新棋盤,當然,他希望這個棋盤儘可能的大。不過小Q還沒有決定是找

一個正方形的棋盤還是一個矩形的棋盤(當然,不管哪種,棋盤必須都黑白相間,即相鄰的格子不同色),所以他

希望可以找到最大的正方形棋盤面積和最大的矩形棋盤面積,從而決定哪個更好一些。於是小Q找到了即將參加全

國資訊學競賽的你,你能幫助他麼?

Input

  第一行包含兩個整數N和M,分別表示矩形紙片的長和寬。接下來的N行包含一個N * M的01矩陣,表示這張矩形

紙片的顏色(0表示白色,1表示黑色)。

Output

  包含兩行,每行包含一個整數。第一行為可以找到的最大正方形棋盤的面積,第二行為可以找到的最大矩形棋

盤的面積(注意正方形和矩形是可以相交或者包含的)。

Sample Input

3 3
1 0 1
0 1 0
1 0 0

Sample Output

4
6

HINT

 

N, M ≤ 2000

 

Source

 

[Submit][Status][Discuss]


HOME Back

 

裸的懸線法求最大矩陣(雖然單調棧也可以做)

對於每個點,我們記錄最遠能到的左端點 l[i][j]

 和右端點 r[i][j] 然後再記錄最遠能往上擴充套件的距離 up[i][j]

然後……還是看程式碼理解一下吧

​​​​​​​​​​​​​​/**************************************************************
    Problem: 1057
    User: lahlah
    Language: C++
    Result: Accepted
    Time:2708 ms
    Memory:64100 kb
****************************************************************/
 
#include<bits/stdc++.h>
#define N 2005
using namespace std;
int n, m, a[N][N], l[N][N], r[N][N], up[N][N], ans1, ans2;
int main(){
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; i ++)
        for(int j = 1; j <= m; j ++) scanf("%d", &a[i][j]), l[i][j] = r[i][j] = j;
     
    for(int i = 1; i <= n; i ++)
        for(int j = 2; j <= m; j ++)
            if(a[i][j] == !a[i][j-1]) l[i][j] = l[i][j-1];//預處理往左最遠能擴充套件的位置
     
    for(int i = 1; i <= n; i ++)
        for(int j = m - 1; j >= 1; j --)
            if(a[i][j] == !a[i][j+1]) r[i][j] = r[i][j+1];//預處理往右最遠能擴充套件的位置
     
    for(int i = 1; i <= n; i ++){
        for(int j = 1; j <= m; j ++){
            up[i][j] = 1;
            if(a[i][j] == !a[i-1][j] && i != 1){//如果可以由上面的擴充套件則擴充套件
                up[i][j] = up[i-1][j] + 1;
                l[i][j] = max(l[i][j], l[i-1][j]);
                r[i][j] = min(r[i][j], r[i-1][j]);
            }
            int w = r[i][j] - l[i][j] + 1, h = up[i][j];//更新答案
            ans1 = max(ans1, w * h);
            ans2 = max(ans2, min(w, h) * min(w, h));
        }
    }
    printf("%d\n%d", ans2, ans1);
    return 0;
}

 有意思