/* 模拟形DP, 没啥好说的, 就是难写 其实我刚开始想的时候是想处理出前缀N 后缀I而后枚举分界线, 这样虽然好写, 可是貌似要多个N的复杂度 因此直接dp便可 将 NOI看作十一个部分, 每一个字母分红三个部分, 而后中间部分必须空着两条, 须要设计两个部分 */ #include<cstdio> #include<algorithm> #include<cstring> #include<iostream> #include<queue> #define ll long long #define N 155 #define M 505 #define mmp make_pair using namespace std; int read() { int nm = 0, f = 1; char c = getchar(); for(; !isdigit(c); c = getchar()) if(c == '-') f = -1; for(; isdigit(c); c = getchar()) nm = nm * 10 + c - '0'; return nm * f; } const int inf = 0x3e3e3e3e; int f[12][N][N], s1[N][N], s2[N][N], s[N], a[M][N], ans, n, m; void DP() { for(int j = 1; j <= m; j++) { for(int i = 1; i <= n; i++) s[i] = s[i - 1] + a[j][i]; //I 右边 for(int l = 1; l <= n; l++) { for(int r = l + 2; r <= n; r++) { f[11][l][r] = max(f[11][l][r], f[10][l][r]) + a[j][l] + a[j][r]; ans = max(ans, f[11][l][r]); // cerr<< ans << "\n"; } } //I 中间 for(int l = 1; l <= n; l++) { for(int r = l + 2; r <= n; r++) { f[10][l][r] = max(f[10][l][r], f[9][l][r]) + s[r] - s[l - 1]; } } //I 前面 for(int l = 1; l <= n; l++) for(int r = l + 2; r <= n; r++) { f[9][l][r] = max(f[9][l][r], f[8][0][0]) + a[j][l] + a[j][r]; } //空格 for(int l = 1; l <= n; l++) for(int r = l + 2; r <= n; r++) f[8][0][0] = max(f[8][0][0], f[7][l][r]); // O右边 for(int l = 1; l <= n; l++) for(int r = l + 2; r <= n; r++) f[7][l][r] = f[6][l][r] + s[r] - s[l - 1]; //O中间 for(int l = 1; l <= n; l++) for(int r = l + 2; r <= n; r++) f[6][l][r] = max(f[6][l][r], f[5][l][r]) + a[j][l] + a[j][r]; // O左边 for(int l = 1; l <= n; l++) for(int r = l + 2; r <= n; r++) f[5][l][r] = f[4][0][0] + s[r] - s[l - 1]; //空格 for(int l = 1; l <= n; l++) for(int r = l + 1; r <= n; r++) f[4][0][0] = max(f[4][0][0], f[3][l][r]); // 前缀最小值优化转移 for(int l = 1; l <= n; l++) { int tmp = -inf; for(int r = l + 1; r <= n; r++) { tmp = max(tmp, f[2][l][r - 1]); f[3][l][r] = max(f[3][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]); f[2][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++) f[1][l][r] = max(0, f[1][l][r]) + s[r] - s[l - 1]; for(int l = 1; l <= n; l++) for(int r = n; r; r--) s2[l][r] = max(f[2][l][r], s2[l][r + 1]); for(int r = 1; r <= n; r++) for(int l = 1; l <= n; l++) s1[l][r] = max(f[1][l][r], s1[l - 1][r]); // for(int i = 1; i <= 11; i++) // { // if(i == 4 || i == 8) // { // cerr << f[i][0][0] << "\n"; // } // else cerr << f[i][1][3] << "\n"; // } } } 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(); memset(f, -inf, sizeof(f)); memset(s1, -inf, sizeof(s1)); memset(s2, -inf, sizeof(s2)); ans = -inf; DP(); cout << ans << "\n"; return 0; }