【BZOJ】1057 [ZJOI2007]棋盘制作(悬线法)

题目

传送门:QWQ

 

 

分析

先把题目给出的矩阵变换一下,如果$ a[i][j] $中$ i+j \mod 2 = 1 $那么就对$ a[i][j] $取一下反。

接着就是求原图中最大的0、1子矩阵

详见lrj蓝书,悬线法维护最大0、1子矩阵。

 

代码

 1 #include<bits/stdc++.h>
 2 #define left lft
 3 #define right rght
 4 using namespace std;
 5 const int maxn=2000;
 6 int left[maxn][maxn], right[maxn][maxn], up[maxn][maxn] ;
 7 int mp[maxn][maxn];
 8 int sqr(int x){return x*x;}
 9 int main(){
10     int n,m;scanf("%d%d",&n,&m);
11     for(int i=1;i<=n;i++)
12         for(int j=1;j<=m;j++){
13             scanf("%d",&mp[i][j]); if((i+j)%2) mp[i][j]^=1;
14     }
15     int ans1=0,ans2=0;
16     for(int i=0;i<=m;i++) right[0][i]=1e9;
17     for(int i=1;i<=n;i++){
18         left[i][1]=0; right[i][m]=m;
19         int le=0,ri=m+1;
20         for(int j=1;j<=m;j++){
21             if(mp[i][j]){
22                 up[i][j]=up[i-1][j]+1; left[i][j]=max(left[i-1][j],le+1);
23 
24             }
25             else{ le=j; }
26         }
27 
28         for(int j=m;j>=1;j--){
29             if(mp[i][j]){
30                 right[i][j]=min(ri-1,right[i-1][j]);
31                 int linelen=right[i][j]-left[i][j]+1 ,rowlen=up[i][j];
32                 ans1=max(ans1,sqr(min(linelen,rowlen)));
33                 ans2=max(ans2,linelen*rowlen);
34             }
35             else{
36                 ri=j; right[i][j]=m;
37             }
38         }
39     }
40 
41     memset(right,0,sizeof(right)); memset(left,0,sizeof(left)); memset(up,0,sizeof(up));
42     for(int i=0;i<=m;i++) right[0][i]=1e9;
43     for(int i=1;i<=n;i++){
44         left[i][1]=0; right[i][m]=m;
45         int le=0,ri=m+1;
46         for(int j=1;j<=m;j++){
47             if(!mp[i][j]){
48                 up[i][j]=up[i-1][j]+1; left[i][j]=max(left[i-1][j],le+1);
49 
50             }
51             else{ le=j; }
52         }
53 
54         for(int j=m;j>=1;j--){
55             if(!mp[i][j]){
56                 right[i][j]=min(ri-1,right[i-1][j]);
57                 int linelen=right[i][j]-left[i][j]+1 ,rowlen=up[i][j];
58                 ans1=max(ans1,sqr(min(linelen,rowlen)));
59                 ans2=max(ans2,linelen*rowlen);
60             }
61             else{
62                 ri=j; right[i][j]=m;
63             }
64         }
65     }
66     printf("%d\n%d",ans1,ans2);
67 
68     return 0;
69 }

 

 

 

posted @ 2018-08-03 19:43  noble_(noblex)  阅读(...)  评论(... 编辑 收藏
/* */