1. 程式人生 > >bzoj1057 [ZJOI2007]棋盤制作

bzoj1057 [ZJOI2007]棋盤制作

stdout 最大的 一個 while 遊戲 cout == 面積 bzoj1057

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

正解:$dp$+單調棧。

首先做一個轉化,把$i+j$同為奇數的點取反,那麽我們的目標就變成了找到最大的全$0$或全$1$正方形和矩形,這裏只考慮全$1$的情況。

正方形很容易,設$f[i][j]$表示以$(i,j)$為右下角的最大正方形邊長,那麽$f[i][j]=min(f[i-1][j-1]+1,mh[i][j],ml[i][j])$。

其中$mh[i][j]$表示$(i,j)$向左延伸的最長長度,$ml[i][j]$表示$(i,j)$向上延伸的最長長度。

矩形其實也不難,我們可以使用單調棧來求最大全$1$矩形,由於是經典問題所以不再贅述。

 1 #include <bits/stdc++.h>
 2 #define il inline
 3 #define RG register
 4 #define ll long long
 5
#define N (2005) 6 7 using namespace std; 8 9 int mh[N][N],ml[N][N],f[N][N],g[N][N],st[N],n,m,ans1,ans2; 10 11 il int gi(){ 12 RG int x=0,q=1; RG char ch=getchar(); 13 while ((ch<0 || ch>9) && ch!=-) ch=getchar(); 14 if (ch==-) q=-1,ch=getchar(); 15 while (ch>=0 && ch<=9) x=x*10+ch-48,ch=getchar(); 16 return q*x; 17 } 18 19 il void pre(){ 20 for (RG int i=1;i<=n;++i) 21 for (RG int j=1;j<=m;++j){ 22 mh[i][j]=g[i][j]?(mh[i][j-1]+1):0; 23 ml[i][j]=g[i][j]?(ml[i-1][j]+1):0; 24 } 25 return; 26 } 27 28 il void work1(){ 29 for (RG int i=1;i<=n;++i) 30 for (RG int j=1;j<=m;++j){ 31 f[i][j]=min(f[i-1][j-1]+1,min(mh[i][j],ml[i][j])); 32 ans1=max(ans1,f[i][j]*f[i][j]); 33 } 34 return; 35 } 36 37 il void work2(){ 38 for (RG int i=1,top;i<=n;++i){ 39 top=0; 40 for (RG int j=1;j<=m+1;++j){ 41 while (top && ml[i][j]<=ml[i][st[top]]) 42 ans2=max(ans2,(j-st[top-1]-1)*ml[i][st[top]]),--top; 43 st[++top]=j; 44 } 45 } 46 return; 47 } 48 49 int main(){ 50 #ifndef ONLINE_JUDGE 51 freopen("chess.in","r",stdin); 52 freopen("chess.out","w",stdout); 53 #endif 54 n=gi(),m=gi(); 55 for (RG int i=1;i<=n;++i) 56 for (RG int j=1;j<=m;++j) 57 g[i][j]=gi()^((i+j)&1); 58 pre(),work1(),work2(); 59 for (RG int i=1;i<=n;++i) 60 for (RG int j=1;j<=m;++j) g[i][j]^=1; 61 pre(),work1(),work2(); 62 cout<<ans1<<endl<<ans2; return 0; 63 }

bzoj1057 [ZJOI2007]棋盤制作