13年国赛一道很有意思的一道题…… 然而和浙江那年省选题蚂蚁寻路思路一致,是巧合?
本题 dp , 从左往右逐列考虑, 将状态分为11种, 每个字符分成3类状态, 间隔有两种状态,我只想说说 N 字符的第二种状态的转移。
如果
l≤x≤r+1 r≤y≤n
我们用坐标可视化这个不等式:
显然可用的
x,y
的区域是一个矩形。我们来看一些性质:
当
l
变化
当
r
变化
由此我们发现先枚举
r
更好, 然后我们尝试维护一个可选区域每一列的最大值。
具体方法是:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 155;
const int INF = 0x3f3f3f3f;
int n , m , g[maxn][510];
int d[3][11][maxn][maxn] , s[510][maxn] , mx[maxn];
int main(int argc, char *argv[]) {
cin>>n>>m;
for(int i=n;i>=1;i--) for(int j=1;j<=m;j++) scanf("%d" , g[i]+j);
for(int i=1;i<=m;i++) for(int j=1;j<=n;j++) s[i][j] = s[i][j-1] + g[j][i];
int res = -INF;
memset(d, -INF, sizeof(d));
for(int i=1;i<=m;i++)
{
int c = i%3 , f = (i-1)%3 , t = (i+1)%3;
memset(d[t], -INF, sizeof(d[0]));
// FOR 0 , 4 , 5 , 6 , 8 , 9 , 10
for(int l=1;l<=n;l++) for(int r=l;r<=n;r++)
{
int s1 = s[i][r] - s[i][l-1] , s2 = g[l][i] + g[r][i];
d[c][0][l][r] = max(d[f][0][l][r], 0) + s1;
if(r-l < 2) continue;
d[c][4][l][r] = d[f][3][0][0] + s1;
d[c][6][l][r] = d[f][5][l][r] + s1;
d[c][5][l][r] = max(d[f][4][l][r], d[f][5][l][r]) + s2;
d[c][8][l][r] = max(d[f][8][l][r], d[f][7][0][0]) + s2;
d[c][9][l][r] = max(d[f][9][l][r], d[f][8][l][r]) + s1;
d[c][10][l][r] = max(d[f][10][l][r], d[f][9][l][r]) + s2;
res = max(res, d[c][10][l][r]);
d[t][7][0][0] = max(d[t][7][0][0], d[c][6][l][r]);
}
// FOR 3 , 7
d[c][3][0][0] = max(d[c][3][0][0], d[f][3][0][0]);
d[c][7][0][0] = max(d[c][7][0][0], d[f][7][0][0]);
// FOR 1
memset(mx, -INF, sizeof(mx));
for(int r=n;r;r--)
{
for(int j=1;j<=n;j++) mx[j] = max(mx[j], d[f][1][j][r]);
for(int l=r,now=mx[r+1];l;l--)
{
now = max(now, mx[l]);
d[c][1][l][r] = max(d[f][1][l][r], now) + s[i][r] - s[i][l-1];
}
for(int l=1,now=-INF;l<=r;l++)
{
d[c][1][l][r] = max(d[c][1][l][r], now + s[i][r] - s[i][l-1]);
now = max(now, d[f][0][l][r]);
}
}
// FOR 2
for(int l=1;l<=n;l++) for(int r=l,now = -INF;r<=n;r++)
{
d[c][2][l][r] = max(d[f][2][l][r], now) + s[i][r] - s[i][l-1];
d[t][3][0][0] = max(d[t][3][0][0], d[c][2][l][r]);
now = max(now, d[f][1][l][r]);
}
}
cout<<res<<endl;
return 0;
}