悬线法 学习笔记
概述
一种简单的 DP 技巧,可以在某些单调栈题中使用,相对单调栈更好理解。
例题
最大子矩形问题。
首先算出 \(l_{i,j},r_{i,j},u_{i,j}\),分别表示一个点向左、右、上可以走多少格,容易递推。
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++)if(a[i][j]=='F')l[i][j]=l[i][j-1]+1,u[i][j]=u[i-1][j]+1;
for(int j=m;j>=1;j--)if(a[i][j]=='F')r[i][j]=r[i][j+1]+1;
}
悬线是指一个点不断向上延伸直到碰到障碍形成的竖线。求出每条悬线左右最多移动到的位置,最大子矩形必然由一条悬线左右移动而成,否则这个矩形可以拓展。
设 \(L_{i,j},R_{i,j}\) 为以一个点开始的悬线可以向左、向右移动多少格,则:
\[L_{i,j}=\begin{cases}\min(l_{i,j},L_{i-1,j})\,&(i-1,j)\text{可选}\\l_{i,j}\,&(i-1,j)\text{不可选}\end{cases}
\]
\[R_{i,j}=\begin{cases}\min(r_{i,j},R_{i-1,j})\,&(i-1,j)\text{可选}\\r_{i,j}\,&(i-1,j)\text{不可选}\end{cases}
\]
那么直接复用 \(l,r\) 数组 DP,最大子矩形的面积即为 \(u_{i,j}\times(L_{i,j}+R_{i,j}-1)\)。
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if(a[i][j]=='R')continue;
if(a[i-1][j]=='F')l[i][j]=min(l[i][j],l[i-1][j]),r[i][j]=min(r[i][j],r[i-1][j]);
ans=max(ans,(l[i][j]+r[i][j]-1)*u[i][j]);
}
}
[[动态规划]]

浙公网安备 33010602011771号