【学习笔记】悬线法

今天发现自己不会悬线法,然后去学习了一下

首先推荐blog

我们发现有些问题是在一个矩形中找到最大的符合某种条件的矩形

\(LGOJ4147\) 为例,这里的某种条件就是矩形中都是 \(F\)

这里思考一种可以\(O(NM)\)解决这类问题的一种方法

先定义一些东西:

有效子矩形:满足条件的子矩形(本题中即矩形中都是 \(F\)

极大有效子矩形:自身无法被任何有效子矩形(除去本身)覆盖的子矩形

(这里说白了就是没法拓展的呗)

最大有效子矩形:所有极大子矩形中最大的一个

为了简化描述,我们把视整个矩形的边上有障碍点

所以我们发现这个极大有效子矩形的边上必然有障碍点(否则接着拓)

这里我们就可以看到有一种方法:

\(l[i][j]\)\((i,j)\)最左边没有障碍点的位置

同理\(r[i][j]\)是右边的

再定义:\(up[i][j]\)是该矩形的高

因为一般算法的对象是求最大的矩形,那么会有如下的转移:

l[i][j]=max(l[i][j],l[i-1][j]);
r[i][j]=min(r[i][j],r[i-1][j]);
up[i][j]=up[i-1][j]+1;

(个人建议去链接里看,比我说的少还清楚,可以跳过一些引入的部分)

然后每个\((i,j)\)更新ans就好了

例题:

\(LGOJ4147\) 玉蟾宫

#include<bits/stdc++.h>
using namespace std;
#define int long long
namespace yspm{
	inline int read()
	{
		int res=0,f=1; char k;
		while(!isdigit(k=getchar())) if(k=='-') f=-1;
		while(isdigit(k)) res=res*10+k-'0',k=getchar();
		return res*f;
	}
	const int N=1e3+10;
	int g[N][N],n,m,up[N][N],l[N][N],r[N][N],ans;
	
	signed main()
	{
		n=read(); m=read();
		for(int i=1;i<=n;++i)
		{
			for(int j=1;j<=m;++j)
			{
				char t; cin>>t;
				g[i][j]=t=='F';
				up[i][j]=1; l[i][j]=r[i][j]=j;
			}
		}
		for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) if(g[i][j]&&g[i][j-1]) l[i][j]=l[i][j-1];
		for(int i=1;i<=n;++i) for(int j=m;j>=1;--j) if(g[i][j]&&g[i][j+1]) r[i][j]=r[i][j+1];
		for(int i=1;i<=n;++i)
		{
			for(int j=1;j<=m;++j)
			{
				if(i>1&&g[i][j]&&g[i-1][j])
				{
					l[i][j]=max(l[i][j],l[i-1][j]);
					r[i][j]=min(r[i][j],r[i-1][j]);
					up[i][j]=up[i-1][j]+1;
				} ans=max(ans,up[i][j]*(r[i][j]-l[i][j]+1));
			}
		}cout<<ans*3<<endl;
		return 0;
	}
}
signed main(){return yspm::main();}

别的都去 \(LGOJ\) 上面看吧

猜你喜欢

转载自www.cnblogs.com/yspm/p/12632612.html