《根据数据范围猜做法系列》
首先感受一下题意,像一个DP。。。
然后观察一下数据范围,感觉应该是个三次方的DP。。
然后发现
n
比
然后观察一下图形,发现了非常奇妙的性质。。
可以分成这11部分,然后用
fi
表示第
i
块,枚举列进行转移。
大概有以下转移:
然后大力DP就好了。。。
#include<iostream>
#include<cstdio>
#include<cstring>
#define clear(a) memset(a,-63,sizeof(a))
using namespace std;
const int N=155;
const int M=505;
int n,m,f4,f8,ans,INF;
int a[M][N],s[N];
int f1[N][N],f2[N][N],f3[N][N],f5[N][N],f6[N][N],f7[N][N],f9[N][N],f10[N][N],f11[N][N],s1[N][N],s2[N][N];
inline int read()
{
int a=0,f=1; char c=getchar();
while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}
while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}
return a*f;
}
int main()
{
n=read(); m=read();
for (int i=1;i<=n;i++)
for (int j=1;j<=m;j++)
a[j][n-i+1]=read();
clear(f1); clear(f2); clear(f3); clear(f5); clear(f6); clear(f7); clear(f9); clear(f10); clear(f11); clear(s1); clear(s2);
INF=-f1[0][0]; f4=f8=ans=-INF;
for (int j=1;j<=m;j++)
{
for (int i=1;i<=n;i++) s[i]=s[i-1]+a[j][i];
for (int l=1;l<=n;l++)
for (int r=l+2;r<=n;r++)
ans=max(ans,f11[l][r]=max(f11[l][r],f10[l][r])+a[j][l]+a[j][r]);
for (int l=1;l<=n;l++)
for (int r=l+2;r<=n;r++)
f10[l][r]=max(f10[l][r],f9[l][r])+s[r]-s[l-1];
for (int l=1;l<=n;l++)
for (int r=l+2;r<=n;r++)
f9[l][r]=max(f9[l][r],f8)+a[j][l]+a[j][r];
for (int l=1;l<=n;l++)
for (int r=l+2;r<=n;r++)
f8=max(f8,f7[l][r]);
for (int l=1;l<=n;l++)
for (int r=l+2;r<=n;r++)
f7[l][r]=f6[l][r]+s[r]-s[l-1];
for (int l=1;l<=n;l++)
for (int r=l+2;r<=n;r++)
f6[l][r]=max(f6[l][r],f5[l][r])+a[j][l]+a[j][r];
for (int l=1;l<=n;l++)
for (int r=l+2;r<=n;r++)
f5[l][r]=f4+s[r]-s[l-1];
for (int l=1;l<=n;l++)
for (int r=l+1;r<=n;r++)
f4=max(f4,f3[l][r]);
for (int l=1;l<=n;l++)
{
int tmp=-INF;
for (int r=l+1;r<=n;r++)
tmp=max(tmp,f2[l][r-1]),f3[l][r]=max(f3[l][r],tmp)+s[r]-s[l-1];
}
for (int r=1;r<=n;r++)
{
int tmp=s2[r+1][r];
for (int l=r;l;l--)
tmp=max(tmp,s2[l][r]),f2[l][r]=max(s1[l-1][r],tmp)+s[r]-s[l-1];
}
for (int l=1;l<=n;l++)
for (int r=l;r<=n;r++)
f1[l][r]=max(0,f1[l][r])+s[r]-s[l-1];
for (int l=1;l<=n;l++)
for (int r=n;r;r--)
s2[l][r]=max(f2[l][r],s2[l][r+1]);
for (int r=1;r<=n;r++)
for (int l=1;l<=n;l++)
s1[l][r]=max(f1[l][r],s1[l-1][r]);
}
cout << ans << endl;
return 0;
}