题目描述
帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的 n imes mn×m 的矩阵,矩阵中的每个元素 a_{i,j}ai,j 均为非负整数。游戏规则如下:
- 每次取数时须从每行各取走一个元素,共 nn 个。经过 mm 次后取完矩阵内所有元素;
- 每次取走的各个元素只能是该元素所在行的行首或行尾;
- 每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值 imes 2^i×2i ,其中 ii 表示第 ii 次取数(从 11 开始编号);
- 游戏结束总得分为 mm 次取数得分之和。
帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分。
输入输出格式
输入格式:
输入文件包括 n+1n+1 行:
第 11 行为两个用空格隔开的整数 nn 和 mm 。
第 2~n+12 n+1 行为 n imes mn×m 矩阵,其中每行有 mm 个用单个空格隔开的非负整数。
输出格式:
输出文件仅包含 11 行,为一个整数,即输入矩阵取数后的最大得分。
输入输出样例
说明
NOIP 2007 提高第三题
数据范围:
60%的数据满足: 1le n, m le 301≤n,m≤30 ,答案不超过 10^{16}1016
100%的数据满足: 1le n, m le 801≤n,m≤80 , 0 le a_{i,j} le 10000≤ai,j≤1000
1 #include <cstdio> 2 #include <algorithm> 3 #include <cstring> 4 #include <math.h> 5 #include <iostream> 6 7 using namespace std; 8 9 struct num { 10 int a[35]; 11 num() { memset(a, 0, sizeof(a)); } 12 num(int p) { 13 memset(a, 0, sizeof(a)); 14 int i = 1; 15 while (p != 0) { 16 a[i] = p % 10; 17 p /= 10; 18 i++; 19 } 20 a[0] = i - 1; 21 } 22 num operator +(num b) { 23 int l = max(a[0], b.a[0]); 24 num c; 25 for (int i = 1; i <= l; i++) { 26 c.a[i] += a[i] + b.a[i]; 27 if (c.a[i] > 9) { 28 c.a[i + 1]++; 29 c.a[i] -= 10; 30 if (i == l)l++; 31 } 32 } 33 c.a[0] = l; 34 return c; 35 } 36 void print() { 37 printf("%d", a[a[0]]); 38 for (int i = a[0]-1; i >= 1; i--) 39 printf("%d", a[i]); 40 printf(" "); 41 } 42 }; 43 bool operator <(num p,num b) { 44 if (p.a[0] > b.a[0]) 45 return false; 46 if (p.a[0] < b.a[0]) 47 return true; 48 for (int i = p.a[0]; i >= 1; i--) 49 { 50 if (p.a[i] < b.a[i]) 51 return true; 52 if (p.a[i] > b.a[i]) 53 return false; 54 } 55 return false; 56 } 57 58 num ans; 59 int n, m; 60 int mat[100]; 61 num dp[100][100]; 62 63 int main() 64 { 65 scanf("%d%d", &n, &m); 66 for (int i = 1; i <= n; i++) { 67 memset(dp, 0, sizeof(dp)); 68 for (int j = 1; j <= m; j++) 69 { 70 scanf("%d", &mat[j]); 71 dp[j][j] = mat[j]; 72 } 73 for(int j=2;j<=m;j++) 74 for (int k = 1; k <= m - j + 1; k++) 75 dp[k][k + j - 1] = max(dp[k][k + j - 1], max(num(mat[k]) + dp[k + 1][k + j - 1]+ dp[k + 1][k + j - 1], num(mat[k + j - 1]) + dp[k][k + j - 2]+ dp[k][k + j - 2])); 76 ans =ans+dp[1][m]+dp[1][m]; 77 } 78 ans.print(); 79 return 0; 80 }
注意:
难点在于高精度。看到有人用int128但我并不会用orz。记得在计概课做过此题,当时数据没那么大……所以一开始写的版本全都没有考虑数据大到一定要用高精(int->long->ll->高精)
高精度可以用mod进行优化,感觉好神奇(在我的代码中并未体现,回过头来再试试吧)
很多人把0的情况单列了,其实不用,只要考虑到了在 print() 函数中稍作改动即可( line:37 )
WA:
1.循环里没有重置dp…………debug了很久,感觉我好像总会发生这样的错误
2.结构体里那个数组一定要开大,最大数据达到30位,我就开到30位……于是RE