题目大意: 有一块石头,描述为一个
n
×
n
n\times n
n×n 的网格,.
表示这一格完好无损,*
表示这一格损坏了,要在没有损坏的格子上雕一个8
,具体就是雕出上下两个矩形,上矩形的底边是下矩形的顶边的子集,要求两个矩形的面积之积最大。
题解
容易想到,这是个要求优化枚举顺序的题目。
设
f
1
[
i
]
[
j
]
[
k
]
f1[i][j][k]
f1[i][j][k] 表示以第
i
i
i 行的
j
j
j 到
k
k
k 作为上矩形的底边,上矩形的高是多少。那么也就是从
j
,
k
j,k
j,k 出发向上枚举一下,找到最高的
j
′
,
k
′
j',k'
j′,k′ 满足
j
′
j'
j′ 到
k
′
k'
k′ 中间没有*
,这个可以直接通过
f
[
i
−
1
]
[
j
]
[
k
]
f[i-1][j][k]
f[i−1][j][k] 得到。
注意,一开始求
f
1
[
i
]
[
j
]
[
k
]
f1[i][j][k]
f1[i][j][k] 时,因为要利用
f
[
i
−
1
]
[
j
]
[
k
]
f[i-1][j][k]
f[i−1][j][k] 的信息,所以先不考虑
j
j
j 到
k
k
k 中间有没有*
。
然后同样的设 f 2 [ i ] [ j ] [ k ] f2[i][j][k] f2[i][j][k] 表示以 i i i 行 j j j ~ k k k 作为下矩形顶边时,下矩形的高。最后枚举下矩形的顶边 i , j , k i,j,k i,j,k,下矩形的面积就是 ( f 2 [ i ] [ j ] [ k ] − 2 ) × ( k − j − 1 ) (f2[i][j][k]-2)\times (k-j-1) (f2[i][j][k]−2)×(k−j−1)(因为这题中 边不计入面积),然后找到满足 j ′ ≥ j , k ′ ≤ k j'\geq j,k'\leq k j′≥j,k′≤k,且 ( f 1 [ i ] [ j ′ ] [ k ′ ] − 2 ) × ( k ′ − j ′ − 1 ) (f1[i][j'][k']-2)\times (k'-j'-1) (f1[i][j′][k′]−2)×(k′−j′−1) 最大的 f 1 f1 f1,将这两个面积乘起来更新答案即可。
要找到这样的 f 1 f1 f1,只需要求出 f 1 f1 f1 后再处理一下就好,不需要数据结构来维护。
然后愉快地发现 M L E MLE MLE 了 5 5 5 个点。
于是考虑去掉 f 2 f2 f2 数组,在求 a n s ans ans 的时候顺便求出来就好了。
代码如下:
#include <cstdio>
#include <cstdlib>
#define maxn 302
int n,sum[maxn][maxn],ans=0;
char s[maxn][maxn];
int f[maxn][maxn][maxn];
inline int max(int x,int y){return x>y?x:y;}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%s",s[i]+1);
for(int j=1;j<=n;j++)
sum[i][j]=sum[i][j-1]+(s[i][j]=='*');
}
for(int j=1;j<=n;j++)
for(int k=j+2;k<=n;k++)
for(int i=1,tot=0;i<=n;i++)
{
if(s[i][j]=='.'&&s[i][k]=='.')tot=(tot?tot+1:sum[i][j]==sum[i][k]);
else tot=0; f[i][j][k]=tot;
}
for(int i=1;i<=n;i++)//上面所谓的"处理一下",也就是直接将f[i][j][k]
for(int len=2;len<n;len++)//的值直接变成j~k范围内面积最大矩形的面积
for(int j=1;j<=n;j++)
if(j-len>=1&&sum[i][j-len]==sum[i][j])
f[i][j-len][j]=max((f[i][j-len][j]-2)*(len-1),
max(f[i][j-len+1][j],f[i][j-len][j-1]));
for(int j=1;j<=n;j++)
for(int k=j+2;k<=n;k++)
for(int i=n,tot=0;i>=1;i--)
{
if(s[i][j]=='.'&&s[i][k]=='.')tot=(tot?tot+1:sum[i][j]==sum[i][k]); else tot=0;
ans=max(ans,(tot-2)*(k-j-1)*f[i][j][k]);
}
if(!ans)ans=-1;printf("%d",ans);
}