来自FallDream的博客,未经允许,请勿转载,谢谢。
小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想要知道,他能画出的最大幸运度是多少。
n<=150 m<=500
可以按照列下来形状的不同分成11块(N分成3块,O分成3块,I分成3块,然后中间两个间隔) 然后大力DP
N的处理比较复杂,可以开类似"一个坐标是x,另一个坐标大/小等于y的最大值"的dp数组来转移
#include<iostream> #include<cstdio> #include<cstring> #define rint register int #define INF 2000000000 #define N 150 using namespace std; inline int read() { int x = 0 , f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar();} while(ch >= '0' && ch <= '9'){x = x * 10 + ch - '0';ch = getchar();} return x * f; } int f1[2][N+5][N+5],f2[2][N+5][N+5],f3[2][N+5][N+5],f4[2],f5[2][N+5][N+5],f6[2][N+5][N+5],mx1[2][N+5][N+5],mx3[2][N+5][N+5]; int f7[2][N+5][N+5],f8[2],f9[2][N+5][N+5],f10[2][N+5][N+5],f11[2][N+5][N+5],n,m,s[N+5][550],ans=-INF,mx2[2][N+5][N+5]; inline void R(int&x,int y){y>x?x=y:0;} inline int sum(int x1,int y1,int x2,int y2){return s[x2][y2]+s[x1-1][y1-1]-s[x1-1][y2]-s[x2][y1-1];} void Clear(int k) { f4[k]=f8[k]=-INF; memset(f1[k],128,sizeof(f1[k])); memset(f2[k],128,sizeof(f2[k])); memset(f3[k],128,sizeof(f3[k])); memset(f5[k],128,sizeof(f5[k])); memset(f6[k],128,sizeof(f6[k])); memset(f7[k],128,sizeof(f7[k])); memset(f9[k],128,sizeof(f9[k])); memset(f10[k],128,sizeof(f10[k])); memset(f11[k],128,sizeof(f11[k])); memset(mx1[k],128,sizeof(mx1[k])); memset(mx2[k],128,sizeof(mx2[k])); memset(mx3[k],128,sizeof(mx3[k])); } int main() { Clear(0);Clear(1); n=read();m=read(); for(rint i=1;i<=n;++i) for(rint j=1;j<=m;++j) s[i][j]=read()+s[i-1][j]+s[i][j-1]-s[i-1][j-1]; for(rint i=1,a=1,b=0;i<=m;++i) { for(rint j=1;j<=n;++j) { int Mx=mx3[b][j-1][j-1]; for(rint k=j;k<=n;++k) { Mx=max(Mx,mx3[b][k][j]); int sum1=sum(j,i,k,i),sum2=sum(j,i,j,i)+sum(k,i,k,i); R(f1[a][j][k],max(f1[b][j][k],0)+sum1); R(f2[a][j][k],mx1[b][j][k+1]+sum1); R(f2[a][j][k],Mx+sum1); R(f3[a][j][k],mx2[b][k][j+1]+sum1); R(f3[a][j][k],f3[b][j][k]+sum1); R(f4[a],f3[b][j][k]); R(f4[a],f4[b]);R(f8[a],f8[b]); R(f8[a],f7[b][j][k]); if(j+1<k) { R(f5[a][j][k],f4[b]+sum1); R(f6[a][j][k],max(f6[b][j][k],f5[b][j][k])+sum2); R(f7[a][j][k],f6[b][j][k]+sum1); R(f9[a][j][k],max(f8[b],f9[b][j][k])+sum2); R(f10[a][j][k],max(f9[b][j][k],f10[b][j][k])+sum1); R(f11[a][j][k],max(f11[b][j][k],f10[b][j][k])+sum2); } R(ans,f11[a][j][k]); } } for(rint j=1;j<=n;++j) for(rint k=n;k>=j;--k) mx1[a][j][k]=max(mx1[a][j][k+1],f1[a][j][k]); for(rint j=n;j;--j) for(rint k=j;k;--k) mx2[a][j][k]=max(mx2[a][j][k+1],f2[a][k][j]); for(rint j=1;j<=n;j++) for(rint k=1;k<=j;++k) mx3[a][j][k]=max(mx3[a][j][k-1],f2[a][k][j]); swap(a,b);Clear(a); } printf("%d ",ans); return 0; }