【LuoguP1169 bzoj1057】[ZJOI2007]棋盘制作
首先把矩阵转化一下,把横纵坐标和为偶数点的值取反,这样就转化成求最大的'0'或'1'矩阵。
这道题每个数字是在格子内的,不能在边界包含障碍点。
求最大的0矩阵时,把1作为障碍点。求1同理。
然后求最接近的就可以用树状数组求解啦~
1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4 #include<iostream>
5 #include<algorithm>
6 using namespace std;
7
8 const int N=2100,Inf=(int)1e9;
9 int n,m,a1,a2;
10 int a[N][N],l[N][N],r[N][N],last[N][N],cl[N][N],cr[N][N];
11
12
13 int minn(int x,int y){return x<y ? x:y;}
14 int maxx(int x,int y){return x>y ? x:y;}
15
16 void add(int x,int y,int d)
17 {
18 for(int i=y;i<=m;i+=(i&(-i))) cl[x][i]=maxx(cl[x][i],d);
19 for(int i=y;i>=1;i-=(i&(-i))) cr[x][i]=minn(cr[x][i],d);
20 }
21
22 int get(int x,int y,int tmp)
23 {
24 if(tmp==0)
25 {
26 int ans=0;
27 for(int i=y-1;i>=1;i-=(i&(-i))) ans=maxx(ans,cl[x][i]);
28 if(ans==0) return 1;
29 else return ans+1;
30 }
31 else
32 {
33 int ans=Inf;
34 for(int i=y+1;i<=m;i+=(i&(-i))) ans=minn(ans,cr[x][i]);
35 if(ans>=Inf) return m;
36 else return ans-1;
37 }
38 }
39
40 void solve(int tmp)
41 {
42 memset(cl,0,sizeof(cl));
43 memset(cr,63,sizeof(cr));
44 for(int i=1;i<=n;i++)
45 for(int j=1;j<=m;j++)
46 {
47 if(a[i][j]==tmp) add(i,j,j);
48 }
49 memset(l[0],0,sizeof(l[0]));
50 memset(r[0],63,sizeof(r[0]));
51 for(int i=1;i<=n;i++)
52 {
53 for(int j=1;j<=m;j++)
54 {
55 if(a[i][j]==tmp) continue;
56 if(a[i-1][j]==tmp)
57 {
58 l[i][j]=get(i,j,0);//debug
59 r[i][j]=get(i,j,1);//debug
60 last[i][j]=i-1;
61 }
62 else
63 {
64 l[i][j]=maxx(l[i-1][j],get(i,j,0));
65 r[i][j]=minn(r[i-1][j],get(i,j,1));
66 last[i][j]=last[i-1][j];
67 }
68 int xx=r[i][j]-l[i][j]+1;
69 int yy=i-last[i][j];
70 a1=maxx(a1,minn(xx,yy)*minn(xx,yy));
71 a2=maxx(a2,xx*yy);
72 }
73 }
74 }
75
76 int main()
77 {
78 freopen("a.in","r",stdin);
79 scanf("%d%d",&n,&m);
80 a1=0;a2=0;
81 for(int i=1;i<=n;i++)
82 for(int j=1;j<=m;j++)
83 {
84 scanf("%d",&a[i][j]);
85 if((i+j)%2==0) a[i][j]^=1;
86 }
87 solve(1);
88 solve(0);
89 printf("%d\n%d\n",a1,a2);
90 return 0;
91 }