/*
分析:
对于n行输入,各行之间是独立的,只需要找到各行的最大值,它们的和即为答案。
由于:1<=n, m<=80,0<=aij<=1000,所以最大会出现 1000*(2^80) => 高精度计算
dp[i][j] := 每行取第i到j个数可得到的最大值。
对于输入的任一行a[m],第x次取数的状态转移为:
dp[i][j] = 2*max(dp[i+1][j]+arr[i],dp[i][j-1]+arr[j])
(正常取数是由外向内,但步长是由小到大,相当于取数是由内向外,所以2要乘在外面,这样倍数会自然乘上)
*/
1 #include <iostream>
2 #include <cstdlib>
3 #include <cstdio>
4 #include <cstddef>
5 #include <iterator>
6 #include <algorithm>
7 #include <locale>
8 #include <cmath>
9 #include <vector>
10 #include <cstring>
11 using namespace std;
12 const int INF = 0x3f3f3f3f;
13 const int MaxN = 85;
14 const int MaxLen = 30;
15
16 int n, m;
17
18 struct node
19 {
20 int arr[MaxLen];
21 int len;
22 node ()
23 {
24 memset(arr, 0, sizeof(arr));
25 len = 0;
26 }
27 };
28
29 int arr[MaxN];
30
31 // a*2
32 node Mul(node a)
33 {
34 int carry = 0;
35 for (int i = 0; i < a.len; ++i)
36 {
37 a.arr[i] = (a.arr[i] << 1) + carry;
38 carry = a.arr[i] / 10;
39 a.arr[i] %= 10;
40 }
41 if (carry != 0)
42 {
43 a.arr[a.len] = carry;
44 ++(a.len);
45 }
46 return a;
47 }
48
49 node Add(node a, int val)
50 {
51 int carry = 0;
52 for (int i = 0; i < a.len; ++i) {
53 a.arr[i] += (val % 10 + carry);
54 val /= 10;
55 carry = a.arr[i] / 10;
56 a.arr[i] %= 10;
57 }
58 while (val)
59 {
60 a.arr[a.len] += (val % 10 + carry);
61 val /= 10;
62 carry = a.arr[a.len] / 10;
63 a.arr[a.len] %= 10;
64 ++(a.len);
65 }
66 if (carry)
67 {
68 a.arr[a.len] = carry;
69 ++(a.len);
70 }
71 return a;
72 }
73
74
75 node Add(node a, node b)
76 {
77 node tmp;
78 int carry = 0;
79 int len = max(a.len, b.len);
80 for (int i = 0; i < len; ++i)
81 {
82 tmp.arr[i] = a.arr[i] + b.arr[i] + carry;
83 carry = tmp.arr[i] / 10;
84 tmp.arr[i] = tmp.arr[i] % 10;
85 ++(tmp.len);
86 }
87 if (carry != 0)
88 {
89 tmp.arr[tmp.len] = carry;
90 ++(tmp.len);
91 }
92
93 return tmp;
94 }
95
96 node Cmp(node a, node b)
97 {
98 if (a.len < b.len)
99 {
100 return b;
101 }
102 if (a.len > b.len)
103 {
104 return a;
105 }
106
107 for (int i = a.len - 1; i >= 0; --i)
108 {
109 if (a.arr[i] == b.arr[i]) continue;
110 if (a.arr[i] > b.arr[i])
111 {
112 return a;
113 }
114 else {
115 return b;
116 }
117 }
118 return a;
119 }
120
121
122 int main()
123 {
124 node ans;
125 cin >> n >> m;
126 for (int tn = 0; tn < n; ++tn)
127 {
128 node dp[MaxN][MaxN];
129 for (int tm = 0; tm < m; ++tm)
130 {
131 cin >> arr[tm];
132 // 初始化:dp[i][i] = (arr[i]<<1)
133 int tmp = (arr[tm] << 1);
134 // 不用while循环,防止 tmp=0
135 do
136 {
137 dp[tm][tm].arr[dp[tm][tm].len] = tmp % 10;
138 ++(dp[tm][tm].len);
139 tmp /= 10;
140 } while (tmp);
141 }
142 for (int k = 1; k < m; ++k)
143 {
144 for (int i = 0; (i + k) < m; ++i)
145 {
146 /*node tmp1 = Add(dp[i + 1][i + k], arr[i]);
147 node tmp2 = Mul(Add(dp[i + 1][i + k], arr[i]));*/
148 dp[i][i + k] = Mul(Cmp(Add(dp[i + 1][i + k], arr[i]), Add(dp[i][i + k - 1], arr[i+k])));
149 }
150 }
151 ans = Add(ans, dp[0][m - 1]);
152 }
153 for (int i = ans.len - 1; i >= 0; --i)
154 {
155 cout << ans.arr[i];
156 }
157 cout << endl;
158
159
160 #ifdef HOME
161 cerr << "Time elapsed: " << clock() / CLOCKS_PER_SEC << " ms" << endl;
162 #endif
163 return 0;
164 }