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;
}
posted @ 2023-12-18 18:16  L01001101  阅读(7)  评论(0)    收藏  举报