今天发现自己不会悬线法,然后去学习了一下
首先推荐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\) 上面看吧