1. 程式人生 > >18.7.27 luogu P1005 矩陣取數遊戲

18.7.27 luogu P1005 矩陣取數遊戲

輸入輸出 圖片 編號 矩陣 algo != 答案 技術分享 ems

題目描述

帥帥經常跟同學玩一個矩陣取數遊戲:對於一個給定的 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,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("\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

18.7.27 luogu P1005 矩陣取數遊戲