Solution - P3135
\(\color{3498DB}\text{P3135 [USACO16JAN] Fort Moo P}\)
看到题目,首先可以想到 \(O(n^2m^2)\) 的枚举:
枚举矩阵的两条横边所处的行,两条竖边所在的列,然后再通过分别对行和对列的前缀和判断矩阵是否满足条件即可。
但我们发现 \(n,m \leq 300\) 的数据范围会超时。
考虑减少一层对于列的枚举。
通过枚举两个行确定矩阵的高,接着将列扫一遍确定最大且满足条件的线段,此线段即作为矩阵的边。
然后更新答案即可。
时间复杂度 \(O(n^2m)\)。
#include<cstdio>
#include<cstring>
const int N=210;
int n,m;
int ans;
char a[N][N];
int s[N][N];
inline int read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9')ch=='-'?f=0:0,ch=getchar();
while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
return f?x:-x;
}
inline int max(int a,int b){return a>b?a:b;}
int main(){
n=read(),m=read();
for(int i=1;i<=n;++i)
scanf("%s",a[i]+1);
for(int j=1;j<=m;++j)for(int i=1;i<=n;++i)
s[i][j]=s[i-1][j]+(a[i][j]=='X');
for(int i=1,l,r,_l,_r;i<=n;++i)for(int j=i;j<=n;++j){
l=r=_l=_r=0;//l,r 为最优线段左右端点,_l,_r 为当前线段的左右端点。
for(int k=1;k<=m;++k){
if(a[i][k]=='X'||a[j][k]=='X'){_l=_r=0;continue;}
if(s[j][k]-s[i-1][k]==0)!_l?_l=k:0,_r=k;
r-l<_r-_l?l=_l,r=_r:0;
}
r-l<_r-_l?l=_l,r=_r:0,l?ans=max(ans,(r-l+1)*(j-i+1)):0;
}
printf("%d\n",ans);
return 0;
}
浙公网安备 33010602011771号