LUOGU P4147 玉蟾宫 悬线法

P4147 玉蟾宫

题目背景

有一天,小猫 rainbow 和 freda 来到了湘西张家界的天门山玉蟾宫,玉蟾宫宫主蓝兔盛情地款待了它们,并赐予它们一片土地。

题目描述

这片土地被分成 \(N\times M\) 个格子,每个格子里写着 R 或者 F,R 代表这块土地被赐予了 rainbow,F 代表这块土地被赐予了 freda。

现在 freda 要在这里卖萌。。。它要找一块矩形土地,要求这片土地都标着 F 并且面积最大。

但是 rainbow 和 freda 的 OI 水平都弱爆了,找不出这块土地,而蓝兔也想看 freda 卖萌(她显然是不会编程的……),所以它们决定,如果你找到的最大的土地面积为 \(S\),它们每人给你 \(S\) 两银子。

输入格式

第一行两个整数 \(N\),\(M\),表示矩形土地有 \(N\) 行 \(M\) 列。

接下来 \(N\) 行,每行 \(M\) 个用空格隔开的字符 F 或 R,描述了矩形土地。

输出格式

输出一个整数,表示你能得到多少银子,即 \(3\times S\) 的值。

输入输出样例 #1

输入 #1

5 6 
R F F F F F 
F F F F F F 
R R R F F F 
F F F F F F 
F F F F F F

输出 #1

45

说明/提示

对于 \(50\%\) 的数据,\(1 \leq N, M \leq 200\)。
对于 \(100\%\) 的数据,\(1 \leq N, M \leq 1000\)。


悬线法,一种用来求矩阵中极大矩阵的方法。
也就是矩阵中有些点为障碍点,不能包含在所求矩阵中。那么以每一个点为扩展出的最大矩阵为极大矩阵。所有极大矩阵中最大的一个或多个为最大矩阵。
方法:把每一个障碍点(包含顶边的点)看作一个钉子,从钉子的位置向下悬一根线,当线垂到当前点时,从钉子到当前点的这根线可以不受阻碍的左右移动范围乘以这条线的长度就得到了这个矩阵的面积。当枚举了每一个点时,就可以得了最大矩阵。

水平有限,如果悬线法不明白,可以看一下下面的网址:https://www.luogu.com.cn/article/ajz43w7l

程序中变量的含义和递推关系:
l[i][j]:(i,j)点向左可以延伸到的最远的位置的列号
l[i][j]=l[i][j-1],(如果左边的点不为障碍点)
l[i][j]=i,(如果左边的点为障碍点)
如果当前点就是障碍点的话就不用统计了。
r[i][j]:(i,j)点向右可以延伸到的最远的位置的列号,递推方法如l[i][j],但是递推时j要从大到小

up[i][j]:(i,j)点向上可以延伸到的最远位置的列号,也就是障碍点的下一行
up[i][j]=up[i-1][j],(如果上面的点不是障碍点)
up[i][j]=i,(如果上面的点是障碍点)
同样,如果当前点就是障碍点就可以不统计,这和l[i][j]的递推方法也一样

ll[i][j]:这条悬线可以向左平移的最远列的列号。
ll[i][j]=max(ll[i-1][j],l[i][j]),也就是悬线到上面的点可以向左平移的最远列,和当前点在当前单行内可以向左移动的最远列,那个更近一点。
同样的方法,可以推出rr[i][j]

所以,ans=max(ans,(i-up[i][j]+1)*(rr[i][j]-ll[i][j]+1))


#include<bits/stdc++.h>
using namespace std;
const int maxn=1010;
char s[3];
int ans;
int n,m;
int tu[maxn][maxn];
int l[maxn][maxn],r[maxn][maxn],up[maxn][maxn];
int ll[maxn][maxn],rr[maxn][maxn];
int main()
{
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;++i)
	{
		for(int j=1;j<=m;++j)
		{
			scanf("%s",s);
			if(s[0]=='R')tu[i][j]=0;
			else tu[i][j]=1;
		}
	}
	for(int i=1;i<=n;++i)
	{
		for(int j=1;j<=m;++j)
			if(tu[i][j])
			{
				if(tu[i][j-1])l[i][j]=l[i][j-1];
				else l[i][j]=j;
			}
	}
	for(int i=1;i<=n;++i)
	{
		for(int j=m;j>0;--j)
			if(tu[i][j])
			{
				if(tu[i][j+1])r[i][j]=r[i][j+1];
				else r[i][j]=j;
			}
	}
	for(int i=1;i<=n;++i)
	{
		for(int j=1;j<=m;++j)
			if(tu[i][j])
			{
				if(tu[i-1][j]){up[i][j]=up[i-1][j];ll[i][j]=max(ll[i-1][j],l[i][j]);rr[i][j]=min(rr[i-1][j],r[i][j]);}
				else {up[i][j]=i;ll[i][j]=l[i][j];rr[i][j]=r[i][j];}
				ans=max(ans,(i-up[i][j]+1)*(rr[i][j]-ll[i][j]+1));
			}
	}
	cout<<ans*3<<endl;
	return 0;
}

posted on 2026-09-23 18:58  gryzy  阅读(7)  评论(0)    收藏  举报

导航