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;
}
//あぁ 花火が夜空 綺麗に咲いて ちょっと切なく
//	あぁ 風が時間と ともに流れる
时间: 2024-10-19 04:32:52

BZOJ 3128 Usaco2013 Open Figure Eight的相关文章

数据结构(线段树):BZOJ 3126: [Usaco2013 Open]Photo

3126: [Usaco2013 Open]Photo Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 222  Solved: 116 Description Farmer John has decided to assemble a panoramic photo of a lineup of his N cows (1 <= N <= 200,000), which, as always, are conveniently numbered

BZOJ 3314: [Usaco2013 Nov]Crowded Cows( 单调队列 )

从左到右扫一遍, 维护一个单调不递减队列. 然后再从右往左重复一遍然后就可以统计答案了. ---------------------------------------------------------------------------- #include<bits/stdc++.h> #define rep(i, n) for(int i = 0; i < n; ++i) #define clr(x, c) memset(x, c, sizeof(x)) #define forea

bzoj 3312: [Usaco2013 Nov]No Change

3312: [Usaco2013 Nov]No Change Description Farmer John is at the market to purchase supplies for his farm. He has in his pocket K coins (1 <= K <= 16), each with value in the range 1..100,000,000. FJ would like to make a sequence of N purchases (1 &

BZOJ 3315: [Usaco2013 Nov]Pogo-Cow( dp )

我真想吐槽USACO的数据弱..= = O(n^3)都能A....上面一个是O(n²), 一个是O(n^3) O(n^3)做法, 先排序, dp(i, j) = max{ dp(j, p) } + w( i ) ( t <= p <= j ) 表示跳到第 i 个点, 上一个点是在 j 的最大得分, 其中t是满足条件的最小p. 我们在计算dp(i, j) (1 <= j <= i )时会发现, 随着 j 的递减, t也在不断地减小, 这样我们只要在dp过程中维护h(i, j)表示 m

[BZOJ] 3126: [Usaco2013 Open]Photo

3126: [Usaco2013 Open]Photo Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 318  Solved: 162[Submit][Status][Discuss] Description Farmer John has decided to assemble a panoramic photo of a lineup of his N cows (1 <= N <= 200,000), which, as always,

bzoj 3126: [Usaco2013 Open]Photo——单调队列优化dp

Description 给你一个n长度的数轴和m个区间,每个区间里有且仅有一个点,问能有多少个点 Input * Line 1: Two integers N and M. * Lines 2..M+1: Line i+1 contains a_i and b_i. Output * Line 1: The maximum possible number of spotted cows on FJ's farm, or -1 if there is no possible solution. S

Bzoj 3050: [Usaco2013 Jan]Seating(线段树裸题,然而区间修改标记下放和讨论Push_up很揪心)

题目链接 题意:开始有一个空白的区间,每次可能进行两个操作:A 将一个长度为p的区间加入一段连续空白的位置 L:一个区间恢复空白:要求出A不能进行的次数. 非常裸的线段树题目,用线段树统计最大的空白区间,每个节点需要记录当前区间的最长空白区间,从左端开始的最长空白区间,从右端开始的最长空白区间.Push_up的时候要讨论下,可以分别取[l,mid]和[mid+1,r]的最大空白区间,也可以用[l,mid]的从右端开始的最长空白区间+[mid+1,r]从左端开始的最大空白区间. 每次A的时候,就查

BZOJ 4094 Usaco2013 Dec Optimal Milking 线段树

题目大意:给定n个点排成一排,每个点有一个点权,多次改变某个点的点权并将最大点独立集计入答案,输出最终的答案 开一个线段树,每个点记录四个信息: 区间左端点不选,右端点也不选的最大值 区间左端点选择,右端点不选的最大值 区间左端点不选,右端点选择的最大值 区间左端点选择,右端点也选择的最大值 然后合并时讨论一下就行了 #include <cstdio> #include <cstring> #include <iostream> #include <algorit

【BZOJ】【3697】采药人的路径 &amp; 【3127】【USACO2013 Open】Yin and Yang

点分治 Orz hzwer 倒是比较好想到点分治……然而在方案统计这里,我犯了两个错误…… 1.我比较傻逼的想的是:通过儿子来更新父亲,也就是统计以x为根的子树中xxxx的路径有多少条……这样转移. 然而这实在是太傻逼了,黄学长教做人:从父亲来更新儿子,走到一个节点直接更新路径的统计数,反正我们要的是[经过root的xx路径的数量] 所以可以一遍dfs直接搞出来…… 2.统计方案的方式也想错了……我只考虑了以root作为中转站的路径,然而经过root的路径中,并不只有这种路径是合法的……中转站在