【DP】[NOI2013]书法家
题目描述
小 E 同学非常喜欢书法,他听说 NOI2013 已经开始了,想题一幅 “NOI” 的字送给大家。
小 E 有一张非常神奇的纸,纸可以用一个
矩阵的每个方格有一个整数的幸运值。在格子上面写字可以增加大家的幸运度,幸运度的大小恰好是所有被笔写到的方格的幸运值之和。现在你要在上面写上 “N”, “O”, “I” 三个字母。
下面给出
- “N” 由若干 (
≥3 ) 个边平行于坐标轴的矩形组成,设由K 个矩形组成(标号1∼K ),第i 个矩形的左下角方格坐标设为(Li,Bi) ,右上角坐标设为(Ri,Ti) ,要求满足:Li≤Ri,Bi≤Ti - 对任意
1<i≤K ,有Li=Ri−1+1 - 对任意
3≤i<K ,有Bi−1−1≤Ti≤Ti−1 ,Bi≤Bi−1 B2>B1 ,T2=T1 ,BK−1=BK ,TK−1<TK
- “O” 由一个大矩形
A ,挖去一个小矩形B 得到,这两个矩形的边都平行于坐标轴。设大矩形A 左下角的方格坐标为(u,v) ,长为W ,宽为H ,则小矩形B 满足左下角方格坐标为(u+1,v+1) ,长W−2 ,宽H−2 。要求满足:W≥3,H≥3 u>RK+1
- “I” 为
3 个边平行于坐标轴的从下到上的实心矩形组成,从下到上依次标号为1,2,3 ,第i 个矩形的左下角格子坐标设为(Pi,Qi) ,右上角格子坐标设为(Gi,Hi) ,要求满足:Pi≤Gi,Qi≤Hi P1=P3>u+W ,G1=G3 Q1=H1=Q2−1 ,H2+1=Q3=H3 P1<P2≤G2<G1
下图是一个 “N”,“O”,“I” 的例子。
另外,所有画的图形均不允许超过纸张的边界。现在小 E 想要知道,他能画出的最大幸运度是多少。
输入格式
第一行包含两个正整数
接下来
输出格式
输出一个整数
样例一
input
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
output
24
样例二
input
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
output
-20
样例三
见样例数据下载。
限制与约定
测试点编号 | 幸运值范围 | ||
---|---|---|---|
1 | |||
2 | |||
3 | |||
4 | |||
5 | |||
6 | |||
7 | |||
8 | |||
9 | |||
10 | |||
11 | |||
12 | |||
13 | |||
14 | |||
15 | |||
16 | |||
17 | |||
18 | |||
19 | |||
20 |
对于所有的测试数据,保证
时间限制:
空间限制:
分析
很自然地分成
除了
代码
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define MAXN 150
#define MAXM 500
#define INF 0x3fffffff
int a[MAXN+10][MAXM+10],n,m,blk[MAXM+10][2],f[2][10][MAXN+10][MAXN+10],s[MAXN+10][MAXM+10],tmp[MAXN+10][MAXN+10],ans=-INF;
void Read(int &x){
static char c;
bool f(0);
while(c=getchar(),c!=EOF){
if(c=='-')
f=1;
else if(c>='0'&&c<='9'){
x=c-'0';
while(c=getchar(),c>='0'&&c<='9')
x=x*10+c-'0';
ungetc(c,stdin);
if(f)
x=-x;
return;
}
}
}
void read(){
Read(n),Read(m);
int i,j;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++){
Read(a[i][j]);
s[i][j]=s[i-1][j]+a[i][j];
}
}
void dp(){
int i,j,k;
memset(f[1],0xb0,sizeof f[1]);
for(i=1;i<=n;i++)
for(j=i;j<=n;j++)
f[1][1][i][j]=s[j][1]-s[i-1][1];
blk[1][0]=blk[1][1]=-INF;
for(k=2;k<=m;k++){
memset(f[k&1],0xb0,sizeof f[k&1]);
//N的第一部分
for(i=1;i<=n;i++)
for(j=i;j<=n;j++)
f[k&1][1][i][j]=max(s[j][k]-s[i-1][k],f[(k&1)^1][1][i][j]+s[j][k]-s[i-1][k]);
//N的第二部分
for(i=1;i<=n;i++){
tmp[i][n+1]=-INF;
for(j=n;j>=i;j--)
tmp[i][j]=max(tmp[i][j+1],f[(k&1)^1][1][i][j]);
}
for(i=1;i<=n;i++)
for(j=i;j<=n;j++){
f[k&1][2][i][j]=max(f[k&1][2][i][j],tmp[i][j+1]+s[j][k]-s[i-1][k]);
tmp[i][j]=-INF;
}
for(i=1;i<=n;i++)
for(j=i;j<=n;j++)
tmp[j+1][j+1]=max(tmp[j+1][j+1],f[(k&1)^1][2][i][j]);
for(i=1;i<=n;i++)
for(j=i+1;j<=n;j++)
tmp[i][j]=max(tmp[i][j],tmp[i][j-1]);
for(i=1;i<=n;i++)
for(j=i;j<=n;j++)
f[k&1][2][i][j]=max(f[k&1][2][i][j],tmp[i][j]+s[j][k]-s[i-1][k]);
for(i=1;i<=n;i++)
for(j=i;j<=n;j++)
tmp[i][j]=f[(k&1)^1][2][i][j];
for(j=1;j<=n;j++)
for(i=1;i<j;i++)
tmp[i+1][j]=max(tmp[i+1][j],tmp[i][j]);
for(i=1;i<=n;i++)
for(j=i;j<n;j++)
tmp[i][j+1]=max(tmp[i][j+1],tmp[i][j]);
for(i=1;i<=n;i++)
for(j=i;j<=n;j++)
f[k&1][2][i][j]=max(f[k&1][2][i][j],tmp[i][j]+s[j][k]-s[i-1][k]);
//N的第三部分
for(i=1;i<=n;i++)
for(j=i;j<=n;j++)
tmp[i][j]=f[(k&1)^1][2][i][j];
for(j=1;j<=n;j++)
for(i=j;i>1;i--)
tmp[i-1][j]=max(tmp[i-1][j],tmp[i][j]);
for(i=1;i<=n;i++)
for(j=i+1;j<=n;j++)
f[k&1][3][i][j]=max(f[k&1][3][i][j],max(tmp[i+1][j],f[(k&1)^1][3][i][j])+s[j][k]-s[i-1][k]);
//NO之间空白
blk[k][0]=blk[k-1][0];
for(i=1;i<=n;i++)
for(j=i;j<=n;j++)
blk[k][0]=max(blk[k][0],f[(k&1)^1][3][i][j]);
//O的第一部分
for(i=1;i<=n;i++)
for(j=i+2;j<=n;j++)
f[k&1][4][i][j]=blk[k-1][0]+s[j][k]-s[i-1][k];
//O的第二部分
for(i=1;i<=n;i++)
for(j=i+2;j<=n;j++)
f[k&1][5][i][j]=max(f[(k&1)^1][4][i][j],f[(k&1)^1][5][i][j])+a[i][k]+a[j][k];
//O的第三部分
for(i=1;i<=n;i++)
for(j=i+2;j<=n;j++)
f[k&1][6][i][j]=f[(k&1)^1][5][i][j]+s[j][k]-s[i-1][k];
//OI之间空白
blk[k][1]=blk[k-1][1];
for(i=1;i<=n;i++)
for(j=i;j<=n;j++)
blk[k][1]=max(blk[k][1],f[(k&1)^1][6][i][j]);
//I的第一部分
for(i=1;i<=n;i++)
for(j=i+2;j<=n;j++)
f[k&1][7][i][j]=max(blk[k-1][1],f[(k&1)^1][7][i][j])+a[i][k]+a[j][k];
//I的第二部分
for(i=1;i<=n;i++)
for(j=i+2;j<=n;j++)
f[k&1][8][i][j]=max(f[(k&1)^1][7][i][j],f[(k&1)^1][8][i][j])+s[j][k]-s[i-1][k];
//I的第三部分
for(i=1;i<=n;i++)
for(j=i+2;j<=n;j++){
f[k&1][9][i][j]=max(f[(k&1)^1][8][i][j],f[(k&1)^1][9][i][j])+a[i][k]+a[j][k];
ans=max(ans,f[k&1][9][i][j]);
}
}
}
int main()
{
read();
dp();
printf("%d\n",ans);
}