18.7.27 luogu P1005 矩阵取数游戏

题目描述

帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的 n \times mn×m 的矩阵,矩阵中的每个元素 a_{i,j}ai,j 均为非负整数。游戏规则如下:

  1. 每次取数时须从每行各取走一个元素,共 nn 个。经过 mm 次后取完矩阵内所有元素;
  2. 每次取走的各个元素只能是该元素所在行的行首或行尾;
  3. 每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值 \times 2^i×2i ,其中 ii 表示第 ii 次取数(从 11 开始编号);
  4. 游戏结束总得分为 mm 次取数得分之和。

帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分。

输入输出格式

输入格式:

 

输入文件包括 n+1n+1 行:

第 11 行为两个用空格隔开的整数 nn 和 mm 。

第 2~n+12 n+1 行为 n \times mn×m 矩阵,其中每行有 mm 个用单个空格隔开的非负整数。

 

输出格式:

 

输出文件仅包含 11 行,为一个整数,即输入矩阵取数后的最大得分。

 

输入输出样例

输入样例#1: 
2 3
1 2 3
3 4 2
输出样例#1: 
82

说明

NOIP 2007 提高第三题

数据范围:

60%的数据满足: 1\le n, m \le 301n,m30 ,答案不超过 10^{16}1016
100%的数据满足: 1\le n, m \le 801n,m80 , 0 \le a_{i,j} \le 10000ai,j1000

 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("\n");
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 }
View Code

注意

难点在于高精度。看到有人用int128但我并不会用orz。记得在计概课做过此题,当时数据没那么大……所以一开始写的版本全都没有考虑数据大到一定要用高精(int->long->ll->高精)

高精度可以用mod进行优化,感觉好神奇(在我的代码中并未体现,回过头来再试试吧)

很多人把0的情况单列了,其实不用,只要考虑到了在 print() 函数中稍作改动即可( line:37 )

WA

1.循环里没有重置dp…………debug了很久,感觉我好像总会发生这样的错误

2.结构体里那个数组一定要开大,最大数据达到30位,我就开到30位……于是RE

猜你喜欢

转载自www.cnblogs.com/yalphait/p/9378912.html
今日推荐