BZOJ 3128 Usaco2013 Open Figure Eight

题目大意:给定一个有坏点的矩阵,求能画出来的最大的“8”字形

“8”字形满足:

*数字8由上下两个矩形构成。
*数字8的上下两个矩形都满足至少有一个单元格在矩形内部。
*数字8顶部的矩形的底边必须为底部矩形顶边的子集。
*数字8只能刻在大理石完美无瑕的部分。
*规定数字8的得分为上矩形和下矩形的面积的乘积,它们希望得分能达到最大。

枚举顶部矩形的底边,可以用上一行的底边O(1)转移得到,然后每行O(n^2)向左右拓展

然后枚举底部矩形的顶边,可以用下一行的顶边O(1)转移得到,顶部矩形的最大面积已求出,O(1)更新答案

最终时间复杂度O(n^3) 小心内存

尼玛考试时无解判挂丢了10分。。。简直。。。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M 302
using namespace std;
int n;
long long ans=-1;
char map[M][M];
int sum[M][M];
int f[M][M][M],g[M][M][M];
int Get_Sum(int x1,int y1,int x2,int y2)
{
	return sum[x2][y2]+sum[x1-1][y1-1]-sum[x2][y1-1]-sum[x1-1][y2];
}
int main()
{
	freopen("eight.in","r",stdin);
	freopen("eight.out","w",stdout);
	int i,j,k;
	cin>>n;
	for(i=1;i<=n;i++)
		scanf("%s",map[i]+1);
	for(i=1;i<=n;i++)
		for(j=1;j<=n;j++)
			sum[i][j]=sum[i-1][j]+sum[i][j-1]-sum[i-1][j-1]+(map[i][j]=='*');
	for(i=1;i<=n-2;i++)
		for(j=i+2;j<=n;j++)
		{
			int last=0;
			for(k=1;k<=n;k++)
			{
				if(map[k][i]=='*'||map[k][j]=='*')
					last=0;
				if(!Get_Sum(k,i,k,j))
				{
					if(last)
						f[k][i][j]=(k-last-1)*(j-i-1);
					else
						last=k;
				}
			}
			last=0;
			for(k=n;k;k--)
			{
				if(map[k][i]=='*'||map[k][j]=='*')
					last=0;
				if(!Get_Sum(k,i,k,j))
				{
					if(last)
						g[k][i][j]=(last-k-1)*(j-i-1);
					else
						last=k;
				}
			}
		}
	for(i=1;i<=n;i++)
	{
		for(j=1;j<=n-3;j++)
			for(k=j+3;k<=n;k++)
			{
				if(Get_Sum(i,j,i,k))
					break;
				f[i][j][k]=max(f[i][j][k],f[i][j][k-1]);
			}
		for(j=n;j>=4;j--)
			for(k=j-3;k;k--)
			{
				if(Get_Sum(i,k,i,j))
					break;
				f[i][k][j]=max(f[i][k][j],f[i][k+1][j]);
			}
	}
	for(i=3;i<=n-2;i++)
		for(j=1;j<=n-2;j++)
			for(k=j+2;k<=n;k++)
				if(!Get_Sum(i,j,i,k))
					ans=max(ans,(long long)f[i][j][k]*g[i][j][k]);
	cout<<ans<<endl;
}
//あぁ 花火が夜空 綺麗に咲いて ちょっと切なく
//	あぁ 風が時間と ともに流れる


你可能感兴趣的:(bzoj,BZOJ3128)