悬线法
传送门: luogu4147 玉蟾宫
关于悬线
这个方法似乎是用来搞最大子矩形的~~。
大概就是你想想从点阵中的一个点 ( i , j ) (i, j) (i,j) 向下垂一条线,然后这条线左右摆动直到碰到从这个点能扩展出去的最大的矩形的边界。
记 l e f t i , j left_{i, j} lefti,j 表示从 ( i , j ) (i, j) (i,j) 这个点能到达的最远的左边界,同理我们定义 r i g h t i , j right_{i, j} righti,j 和 u p i , j up_{i, j} upi,j。然后我们就能得到:
l e f t i , j = max { l e f t i , j , l e f t i − 1 , j } r i g h t i , j = min { r i g h t i , j , r i g h t i − 1 , j } u p i , j = u p i − 1 , j + 1 \begin{aligned} left_{i, j} & = \max\{ left_{i, j}, left_{i - 1, j} \} \\ right_{i, j} & = \min\{ right_{i, j}, right_{i - 1, j} \} \\ up_{i, j} & = up_{i - 1, j} +1 \end{aligned} lefti,jrighti,jupi,j=max{lefti,j,lefti−1,j}=min{righti,j,righti−1,j}=upi−1,j+1
初始条件显然是 l e f t i , j = j + 1 , r i g h t i , j = j − 1 , u p i , j = 1 left_{i, j} = j + 1, right_{i, j} = j - 1, up_{i, j} = 1 lefti,j=j+1,righti,j=j−1,upi,j=1。然后还有
然后,就没有然后了。
题
回到这道例题上来,在这道题中,我们显然需要在上述转移的基础上加上一个可以进行转移的条件。也就是是不是都是 F F F。然后就可以直接转移了:
#include<bits/stdc++.h>
using namespace std;
#define MAXN 1010
int n = 0; int m = 0;
char a[MAXN][MAXN];
int l[MAXN][MAXN] = { 0 };
int r[MAXN][MAXN] = { 0 };
int u[MAXN][MAXN] = { 0 };
int main(){
scanf("%d%d", &n, &m); int ans = 0; int cnt = 0;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++){
cin >> a[i][j]; if(a[i][j] == 'F') cnt++;
l[i][j] = r[i][j] = j; u[i][j] = 1;
}
if(cnt == 0) { cout << 0 << '\n'; goto end; }
for(int i = 1; i <= n; i++)
for(int j = 2; j <= m; j++)
if(a[i][j] == a[i][j - 1] and a[i][j] == 'F')
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] and a[i][j] == 'F')
r[i][j] = r[i][j + 1];
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++){
if(i > 1)
if(a[i][j] == a[i - 1][j] and a[i][j] == 'F'){
l[i][j] = max(l[i][j], l[i - 1][j]);
r[i][j] = min(r[i][j], r[i - 1][j]);
u[i][j] = u[i - 1][j] + 1;
}
int a = r[i][j] - l[i][j] + 1;
int b = min(a, u[i][j]);
ans = max(a * u[i][j], ans);
}
cout << 3 * ans << '\n';
end : return 0;
}