/* 模擬形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; }