关于悬线法

悬线法

  传送门: 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,lefti1,j}=min{righti,j,righti1,j}=upi1,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=j1,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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值