BZOJ3241 [Noi2013]书法家/UOJ125

本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作。

本文作者:ljh2000
作者博客:http://www.cnblogs.com/ljh2000-jump/
转载请注明出处,侵权必究,保留最终解释权!

Description

小E同学非常喜欢书法,他听说NOI2013已经开始了,想题一幅“NOI”的字送给大家。

小E有一张非常神奇的纸,纸可以用一个n 行m 列的二维方格矩阵来表示,为了描述方便,我们定义矩阵左下角方格坐标为(1,1) ,右上角方格坐标为(m,n) 。矩阵的每个方格有一个整数的幸运值。在格子上面写字可以增加大家的幸运度,幸运度的大小恰好是所有被笔写到的方格的幸运值之和。现在你要在上面写上 ‘N’,‘O’,‘I’三个字母。

下面给出3个书法字的定义:

1.‘N’由若干(≥3)个边平行于坐标轴的矩形组成,设有K个矩形组成(标号1~K),第i个矩形的左下角方格坐标设为(Li ,Bi) ,右上角坐标设为(Ri ,Ti) ,要求满足:
a)Li<=Ri,Bi<=Ti
b)对任意1<i<=K,有Li=R(i-1)+1
c)对任意3<=i<K,有B(i-1)-1<=Ti<=T(i-1),Bi<=B(i-1);" 
d)B2>B1,T2=T1,B(K-1)=B(K),T(k-1)<T(K)

2.‘O’由一个大矩形A,挖去一个小矩形B得到,这两个矩形的边都平行于坐标轴。设大矩形左下角的方格坐标为(u,v),长为W宽为H,则小矩形B满足左下角方格坐标为(u+1,v+1) ,长W-2 ,宽H-2。要求满足:
a)W>=3,H>=3
b)u>R(K)+1

3.‘I’为3个边平行于坐标轴的从下到上的实心矩形组成,从下到上依次标号为1,2,3,第i 个矩形的左下角格子坐标设为(Pi , Qi ),右上角格子坐标设为(Gi , Hi ),要求满足:
a)Pi<=Gi,Qi<=Hi
b)P1=P3>u+W,G1=G3
c)Q1=H1=Q2-1,H2+1=Q3=H3
d)P1<P2<=G2<G1

下图是一个‘N’,‘O’,‘I’的例子

另外,所有画的图形均不允许超过纸张的边界。现在小E想要知道,他能画出的最大幸运度是多少。

Input

第一行包含两个正整数n和m,分别表示矩阵的行数和列数。
接下来n行,每行有m个整数,第i+1行的第j个数表示格子(j,n-i+1)的幸运值。

Output

输出一个整数T,表示小E能够获得的最大幸运度

Sample Input

【样例输入1】

3 13

1 1 -1 -1 1 -1 1 1 1 -1 1 1 1

1 -1 1 -1 1 -1 1 -1 1 -1 -1 1 -1

1 -1 -1 1 1 -1 1 1 1 -1 1 1 1

【样例输入2】

3 13

-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1

-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1

-1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1 -1

Sample Output

【样例输出1】

24

【样例输出2】

-20

HINT

正解:DP

解题报告:

  复述一遍要求:

  “N”由三个部分组成:最左边是一个矩形,最右边也是一个矩形,中间部分是若干个矩形,要求横坐标必须连续,同时左下、右上纵坐标不升,并且第一个矩形与最左边的上端齐平,最后一个矩形与最右边的下端齐平。

  “O”必须是一个矩形挖掉了中间,得到的一个宽度只能为1的边框。

  “I”只能是上下两个高为1的全等矩形中间夹一个任意形状的矩形(左右边界必须被严格限制在范围内)。

  三个字母中间需要至少隔开一列。

  别的转移都很好做,就是基础DP。唯独N的中间的转移需要仔细考虑。

  分为从1转来和从2转来两种,首先从1转来的话,只需要从n for到1,固定上界的同时保存后缀最大值,更新即可。

  从2转来的话,预处理一下前缀最大值,即下界固定为j,上界为1到i中的最大值。

  更新的时候,让j从i for到n,直接更新即可。

  最后补充一点就是,只能在9处更新答案,空格可以用两个变量存着。

  细节很多,需要仔细调试...

//It is made by ljh2000
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <ctime>
#include <vector>
#include <queue>
#include <map>
#include <set>
#include <string>
#include <complex>
using namespace std;
typedef long long LL;
const int MAXN = 152;
const int MAXM = 520;
const int inf = (1<<30)-1;
int n,m,xing[MAXN][MAXM],dp[MAXN][MAXN],ans;
int f[2][12][MAXN][MAXN],s[MAXN],blank[MAXM][2];
//f[0、1][type][i][j]

inline int getint(){
    int w=0,q=0; char c=getchar(); while((c<‘0‘||c>‘9‘) && c!=‘-‘) c=getchar();
    if(c==‘-‘) q=1,c=getchar(); while (c>=‘0‘&&c<=‘9‘) w=w*10+c-‘0‘,c=getchar(); return q?-w:w;
}

inline void upd(int &x,int y){ if(x<y) x=y; }

inline void work(){
	n=getint(); m=getint(); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) xing[i][j]=getint();
	int tag=1,last,now; ans=-inf; for(int i=0;i<=m;i++) blank[i][0]=blank[i][1]=-inf;
	memset(f,-0x3f,sizeof(f));
	for(int lie=1;lie<=m;lie++) {//枚举列
		last=tag; tag^=1; blank[lie][0]=blank[lie-1][0]; blank[lie][1]=blank[lie-1][1];
		memset(f[tag],-0x3f,sizeof(f[tag]));
		s[0]=0; for(int i=1;i<=n;i++) s[i]=s[i-1]+xing[i][lie];//前缀和
		//1:the left of N
		for(int i=1;i<=n;i++)
			for(int j=i;j<=n;j++) {
				upd(f[tag][1][i][j],s[j]-s[i-1]);
				upd(f[tag][1][i][j],f[last][1][i][j]+s[j]-s[i-1]);
			}

		//2:the middle of N
		memset(dp,-0x3f,sizeof(dp));
		for(int j=1;j<=n;j++) for(int i=1;i<=j;i++) dp[i][j]=max(dp[i-1][j],f[last][2][i][j]);//前缀最大值(下界为j),即下界固定为j,上界为1到i中的最大值
		for(int i=1;i<=n;i++) {//这一次上界i,下界为j
			now=dp[i-1][i-1];//上一次的下界取值最小要为i-1
			//和2相接
			for(int j=i;j<=n;j++){//枚举下界
				upd(now,dp[i][j]);
				upd(f[tag][2][i][j],now);
			}
			//和1相接
			now=-inf;//后缀最大值
			for(int j=n;j>=i;j--) {
				//now保存的是上界为i,下界为j+1到n的矩阵中的1的最大值
				upd(now,f[last][1][i][j+1]);//1和2相接的地方,必须要间隔1。一路往上取max即可
				upd(f[tag][2][i][j],now);
			}
			for(int j=i;j<=n;j++) f[tag][2][i][j]+=s[j]-s[i-1];
		}

		//3:the right of N
		for(int i=1;i<=n;i++) for(int j=i;j<=n;j++) dp[i][j]=f[last][2][i][j];
		for(int j=1;j<=n;j++) for(int i=j;i>=1;i--) upd(dp[i-1][j],dp[i][j]);//后缀max
		for(int i=1;i<=n;i++)
			for(int j=i;j<=n;j++) {
				upd(f[tag][3][i][j],dp[i+1][j]+s[j]-s[i-1]);
				upd(f[tag][3][i][j],f[last][3][i][j]+s[j]-s[i-1]);
			}

		//N和O中间的空行
		for(int i=1;i<=n;i++) for(int j=i;j<=n;j++) upd(blank[lie][0],f[last][3][i][j]);

		//4:the left of O
		for(int i=1;i<=n;i++)
			for(int j=i+2;j<=n;j++)
				f[tag][4][i][j]=blank[lie-1][0]+s[j]-s[i-1];

		//5:the middle of O
		for(int i=1;i<=n;i++)
			for(int j=i+2;j<=n;j++)
				f[tag][5][i][j]=max(f[last][5][i][j],f[last][4][i][j])+xing[i][lie]+xing[j][lie];

		//6:the right of O
		for(int i=1;i<=n;i++)
			for(int j=i+2;j<=n;j++)
				f[tag][6][i][j]=f[last][5][i][j]+s[j]-s[i-1];

		//O和I中间的空行
		for(int i=1;i<=n;i++) for(int j=i;j<=n;j++) upd(blank[lie][1],f[last][6][i][j]);

		//7:the left of I
		for(int i=1;i<=n;i++)
			for(int j=i+2;j<=n;j++)
				f[tag][7][i][j]=max(f[last][7][i][j],blank[lie-1][1])+xing[i][lie]+xing[j][lie];

		//8:the middle of I
		for(int i=1;i<=n;i++)
			for(int j=i+2;j<=n;j++)
				f[tag][8][i][j]=max(f[last][8][i][j],f[last][7][i][j])+s[j]-s[i-1];

		//9:the right of I
		for(int i=1;i<=n;i++)
			for(int j=i+2;j<=n;j++)
				f[tag][9][i][j]=max(f[last][8][i][j],f[last][9][i][j])+xing[i][lie]+xing[j][lie],ans=max(ans,f[tag][9][i][j]);
	}
	printf("%d",ans);
}

int main()
{
    work();
    return 0;
}

  

时间: 2024-12-27 04:27:25

BZOJ3241 [Noi2013]书法家/UOJ125的相关文章

[NOI2013]书法家

题目描述 小E同学非常喜欢书法,他听说NOI2013已经开始了,想题一幅"NOI"的字送给大家. 小E有一张非常神奇的纸,纸可以用一个n 行m 列的二维方格矩阵来表示,为了描述方便,我们定义矩阵左下角方格坐标为(1,1) ,右上角方格坐标为(m,n) .矩阵的每个方格有一个整数的幸运值.在格子上面写字可以增加大家的幸运度,幸运度的大小恰好是所有被笔写到的方格的幸运值之和.现在你要在上面写上 'N','O','I'三个字母. 下面给出3个书法字的定义: 1.'N'由若干(≥3)个边平行于

UOJ#122【NOI2013】树的计数

[NOI2013]树的计数 链接:http://uoj.ac/problem/122 按BFS序来,如果$B_i$与$B_{i-1}$必须在同一层,那么贡献为0,必须在不同层那么贡献为1,都可以贡献为0.5. 因为$B_i$与$B_{i-1}$相邻,所以对方案数的改变最多+1. 必须在不同层,即$D(B_{i-1})>D(B_i)$ 都可以,$B_i$能往下移一层,不改变BFS序以及DFS序: 作为兄弟,父亲必须一样(即$D(B_{i-1})==D(B_i)-1$),不然会改变DFS序. 作为儿

[noi2013]快餐店 基环树dp,单调队列维护最大值和次大值

#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> using namespace std; #define N 220000 #define inf 0x3ffffffffffffffLL typedef long long ll; int v[N],e[N],ne[N],nn,w[N]; void add(int x,int y,int z){ ne[++nn

bzoj 3242: [Noi2013]快餐店 章鱼图

3242: [Noi2013]快餐店 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 266  Solved: 140[Submit][Status] Description 小 T打算在城市C开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小T希望快餐店的地址选在离最远的顾客距离最近 的地方. 快餐店的顾客分布在城市C的N 个建筑中,这N 个建筑通过恰好N 条双向道路连接起来,不存在任何两条道路连接了相同的两

3242: [Noi2013]快餐店 - BZOJ

Description 小T打算在城市C开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小T希望快餐店的地址选在离最远的顾客距离最近的地方. 快餐店的顾客分布在城市C的N 个建筑中,这N 个建筑通过恰好N 条双向道路连接起来,不存在任何两条道路连接了相同的两个建筑.任意两个建筑之间至少存在一条由双向道路连接而成的路径.小T的快餐店可以开设在任一建筑中,也可以开设在任意一条道路的某个位置上(该位置与道路两端的建筑的距离不一定是整数). 现给定城市C的地图(道路

bzoj3242 [Noi2013]快餐店

Description 小T打算在城市C开设一家外送快餐店.送餐到某一个地点的时间与外卖店到该地点之间最短路径长度是成正比的,小T希望快餐店的地址选在离最远的顾客距离最近的地方. 快餐店的顾客分布在城市C的N 个建筑中,这N 个建筑通过恰好N 条双向道路连接起来,不存在任何两条道路连接了相同的两个建筑.任意两个建筑之间至少存在一条由双向道路连接而成的路径.小T的快餐店可以开设在任一建筑中,也可以开设在任意一条道路的某个位置上(该位置与道路两端的建筑的距离不一定是整数). 现给定城市C的地图(道路

3243: [Noi2013]向量内积 - BZOJ

Description 两个d 维向量A=[a1,a2,...,ad]与B=[b1,b2,...,bd]的内积为其相对应维度的权值的乘积和,即: 现有 n 个d 维向量x1,...,xn ,小喵喵想知道是否存在两个向量的内积为k的倍数.请帮助她解决这个问题Input 第一行包含3个正整数n,d,k,分别表示向量的个数,维数以及待检测的倍数.接下来n行每行有d个非负整数,其中第i行的第j个整数表示向量xi的第j维权值xi,j.Output 包含两个整数,用空格隔开.如果存在两个向量xp,xq的内积

3244: [Noi2013]树的计数 - BZOJ

Description 我们知道一棵有根树可以进行深度优先遍历(DFS)以及广度优先遍历(BFS)来生成这棵树的DFS序以及BFS序.两棵不同的树的DFS序有可能相同,并且它们的BFS序也有可能相同,例如下面两棵树的DFS序都是1 2 4 5 3,BFS序都是1 2 3 4 5 现给定一个DFS序和BFS序,我们想要知道,符合条件的有根树中,树的高度的平均值.即,假如共有K棵不同的有根树具有这组DFS序和BFS序,且他们的高度分别是h1,h2,...,hk,那么请你输出(h1+h2..+hk)/

3240: [Noi2013]矩阵游戏

Description 婷婷是个喜欢矩阵的小朋友,有一天她想用电脑生成一个巨大的n行m列的矩阵(你不用担心她如何存储).她生成的这个矩阵满足一个神奇的性质:若用F[i][j]来表示矩阵中第i行第j列的元素,则F[i][j]满足下面的递推式: F[1][1]=1F[i,j]=a*F[i][j-1]+b (j!=1)F[i,1]=c*F[i-1][m]+d (i!=1)递推式中a,b,c,d都是给定的常数. 现在婷婷想知道F[n][m]的值是多少,请你帮助她.由于最终结果可能很大,你只需要输出F[n