/*
codevs 1166 矩阵取数游戏
SB区间dp
dp[l][r] = max (dp[l + 1][r] + number[l], dp[l][r - 1] + number[r]) * 2;
不过要套高精
我用的高精是全部封装好的
可以像平时的int等类型用
缺点就是慢。。。
慢差不多1/3吧。。
*/
#include <iostream>
#include <cstdio>
#include <vector>
#include <iomanip>
#include <cassert>
#include <algorithm>
#define int64 long long
using namespace std;
#define Max 105
const int B = 1000000000;
const int L = 9;
inline int intcmp(int a, int b)
{
if (a > b)
return 1;
else if (a < b)
return -1;
else
return 0;
}
void read (int &now)
{
now = 0;
register char word = getchar ();
while (word < '0' || word > '9')
word = getchar ();
while (word >= '0' && word <= '9')
{
now = now * 10 + word - '0';
word = getchar ();
}
}
struct BigInt
{
vector<int> a;
BigInt(){}
BigInt(int n)
{
while (n > 0)
a.push_back(n % B), n /= B;
}
BigInt(int64 n)
{
while (n > 0)
a.push_back(n % B), n /= B;
}
inline void clr0()
{
while (!a.empty() && a.back() == 0)
a.pop_back();
}
inline BigInt &operator+=(const BigInt &rhs)
{
a.resize(max(a.size(), rhs.a.size()));
int t = 0;
for (int i = 0; i < (int)rhs.a.size(); i++)
{
a[i] += rhs.a[i] + t;
t = a[i] >= B;
a[i] -= B & (-t);
}
for (int i = (int)rhs.a.size(); t != 0 && i < (int)a.size(); i++)
{
a[i] += t;
t = a[i] >= B;
a[i] -= B & (-t);
}
if (t != 0)
a.push_back(t);
return *this;
}
inline BigInt &operator-=(const BigInt &rhs)
{
a.resize(max(a.size(), rhs.a.size()));
int t = 0;
for (int i = 0; i < (int)rhs.a.size(); i++)
{
a[i] -= rhs.a[i] + t;
t = a[i] < 0;
a[i] += B & (-t);
}
for (int i = (int)rhs.a.size(); t != 0 && i < (int)a.size(); i++)
{
a[i] -= t;
t = a[i] < 0;
a[i] += B & (-t);
}
clr0();
return *this;
}
inline BigInt &operator*=(const BigInt &rhs)
{
int na = (int)a.size();
a.resize(na + rhs.a.size());
for (int i = na - 1; i >= 0; i--)
{
int ai = a[i];
int64 t = 0;
a[i] = 0;
for (int j = 0; j < (int)rhs.a.size(); j++)
{
t += a[i + j] + (int64)ai * rhs.a[j];
a[i + j] = t % B;
t /= B;
}
for (int j = (int)rhs.a.size(); t != 0 && i + j < (int)a.size(); j++)
{
t += a[i + j];
a[i + j] = t % B;
t /= B;
}
assert(t == 0);
}
clr0();
return *this;
}
inline BigInt &operator/=(const BigInt &rhs)
{
return *this = div(rhs);
}
inline BigInt &operator%=(const BigInt &rhs)
{
return div(rhs), *this;
}
inline BigInt &shlb(int l = 1)
{
if (a.empty())
return *this;
a.resize(a.size() + l);
for (int i = (int)a.size() - 1; i >= l; i--)
a[i] = a[i - l];
for (int i = 0; i < l; i++)
a[i] = 0;
return *this;
}
inline BigInt &shrb(int l = 1)
{
for (int i = 0; i < (int)a.size() - l; i++)
a[i] = a[i + l];
a.resize(max((int)a.size() - l, 0));
return *this;
}
inline int cmp(const BigInt &rhs) const
{
if (a.size() != rhs.a.size())
return intcmp(a.size(), rhs.a.size());
for (int i = (int)a.size() - 1; i >= 0; i--)
if (a[i] != rhs.a[i])
return intcmp(a[i], rhs.a[i]);
return 0;
}
inline BigInt div(const BigInt &rhs)
{
assert(!rhs.a.empty());
if (rhs > *this)
return 0;
BigInt q, r;
q.a.resize((int)a.size() - (int)rhs.a.size() + 1);
for (int i = (int)a.size() - 1; i > (int)a.size() - (int)rhs.a.size(); i--)
{
r.shlb();
r += a[i];
}
for (int i = (int)a.size() - (int)rhs.a.size(); i >= 0; i--)
{
r.shlb();
r += a[i];
if (r.cmp(rhs) < 0)
q.a[i] = 0;
else
{
int le = 0, ri = B;
while (le != ri)
{
int mi = (le + ri) / 2;
if ((rhs * mi).cmp(r) <= 0)
le = mi + 1;
else
ri = mi;
}
q.a[i] = le - 1;
r -= rhs * q.a[i];
}
}
q.clr0();
*this = r;
return q;
}
friend inline BigInt operator+(const BigInt &lhs, const BigInt &rhs)
{
BigInt res = lhs;
return res += rhs;
}
friend inline BigInt operator-(const BigInt &lhs, const BigInt &rhs)
{
BigInt res = lhs;
return res -= rhs;
}
friend inline BigInt operator*(const BigInt &lhs, const BigInt &rhs)
{
BigInt res = lhs;
return res *= rhs;
}
friend inline BigInt operator/(const BigInt &lhs, const BigInt &rhs)
{
BigInt res = lhs;
return res.div(rhs);
}
friend inline BigInt operator%(const BigInt &lhs, const BigInt &rhs)
{
BigInt res = lhs;
return res.div(rhs), res;
}
friend inline ostream &operator<<(ostream &out, const BigInt &rhs)
{
if (rhs.a.size() == 0)
out << "0";
else
{
out << rhs.a.back();
for (int i = (int)rhs.a.size() - 2; i >= 0; i--)
out << setfill('0') << setw(L) << rhs.a[i];
}
return out;
}
friend inline bool operator<(const BigInt &lhs, const BigInt &rhs)
{
return lhs.cmp(rhs) < 0;
}
friend inline bool operator<=(const BigInt &lhs, const BigInt &rhs)
{
return lhs.cmp(rhs) <= 0;
}
friend inline bool operator>(const BigInt &lhs, const BigInt &rhs)
{
return lhs.cmp(rhs) > 0;
}
friend inline bool operator>=(const BigInt &lhs, const BigInt &rhs)
{
return lhs.cmp(rhs) >= 0;
}
friend inline bool operator==(const BigInt &lhs, const BigInt &rhs)
{
return lhs.cmp(rhs) == 0;
}
friend inline bool operator!=(const BigInt &lhs, const BigInt &rhs)
{
return lhs.cmp(rhs) != 0;
}
};
inline BigInt BigInt_max (BigInt a, BigInt b)
{
return a > b ? a : b;
}
int N, M;
int number[Max];
BigInt dp[Max][Max];
BigInt Answer;
int main (int argc, char *argv[])
{
ios :: sync_with_stdio (false);
read (N);
read (M);
for (int i = 1; i <= N; i ++)
{
for (register int pos = 1; pos <= M; pos ++)
for (register int __pos = 1; __pos <= M; __pos ++)
dp[pos][__pos] = 0;
for (register int pos = 1; pos <= M; pos ++)
{
read (number[pos]);
dp[pos][pos] = 2 * number[pos];
}
for (register int size = 1; size < M; size ++)
for (register int l = 1; l + size <= M; l ++)
{
register int r = l + size;
dp[l][r] = 2 * BigInt_max (dp[l + 1][r] + number[l], dp[l][r - 1] + number[r]);
}
Answer += dp[1][M];
}
cout << Answer;
return 0;
}