此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置。
题目链接:https://www.luogu.org/problem/show?pid=1005
题目描述
帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数。游戏规则如下:
1.每次取数时须从每行各取走一个元素,共n个。m次后取完矩阵所有元素;
2.每次取走的各个元素只能是该元素所在行的行首或行尾;
3.每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值*2^i,其中i表示第i次取数(从1开始编号);
4.游戏结束总得分为m次取数得分之和。
帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分。
输入输出格式
输入格式:
输入文件game.in包括n+1行:
第1行为两个用空格隔开的整数n和m。
第2~n+1行为n*m矩阵,其中每行有m个用单个空格隔开的非负整数。
数据范围:
60%的数据满足:1<=n, m<=30,答案不超过10^16
100%的数据满足:1<=n, m<=80,0<=aij<=1000
输出格式:
输出文件game.out仅包含1行,为一个整数,即输入矩阵取数后的最大得分。
输入输出样例
输入样例#1:
2 3 1 2 3 3 4 2
输出样例#1:
82
说明
NOIP 2007 提高第三题
分析:
本来想用long double水一下,结果long double直接爆炸...30分...long long还有60分呐qwq
不得不重写了高精度...
这是第一道高精度AC了的NOIP题目!!!兴奋!!!
(国王游戏不知道写了多少次,最后还不如打暴力)
除去高精度的话只是个略带难度的DP,全是高精的锅_(:з」∠)_
AC代码:
1 #include<cstdio> 2 #include<algorithm> 3 #include<cmath> 4 #include<cstring> 5 #include<iostream> 6 7 using namespace std; 8 9 int n,m,x; 10 //f[i][j]表示当前除了[i,j]外都已经取完的最大值。 11 12 inline void read(int &x) 13 { 14 char ch = getchar(),c = ch;x = 0; 15 while(ch < ‘0‘ || ch > ‘9‘) c = ch,ch = getchar(); 16 while(ch <= ‘9‘ && ch >= ‘0‘) x = (x<<1)+(x<<3)+ch-‘0‘,ch = getchar(); 17 if(c == ‘-‘) x = -x; 18 } 19 20 struct bign 21 { 22 int len; 23 int num[105]; 24 25 bign(){len = 0;memset(num,0,sizeof(num));} 26 27 void clear() 28 {len = 0;memset(num,0,sizeof(num));} 29 30 }Ans,ans,tmp,note[100],f[100][100],mp[100][100]; 31 32 inline bign Max(bign a,bign b) 33 { 34 if(a.len < b.len) return b; 35 if(a.len > b.len) return a; 36 int len = a.len; 37 for(register int i = len;i >= 1;-- i) 38 { 39 if(a.num[i] > b.num[i]) 40 return a; 41 if(b.num[i] > a.num[i]) 42 return b; 43 } 44 return a; 45 } 46 47 inline int MAX(int a,int b) 48 {return a>b?a:b;} 49 50 bign operator * (bign a,bign b) 51 { 52 ans.clear(); 53 int len = a.len+b.len+1; 54 int x = 0; 55 for(register int i = 1;i <= a.len;++ i) 56 { 57 for(register int j = 1;j <= b.len;++ j) 58 { 59 ans.num[i+j-1] += a.num[i]*b.num[j]+x; 60 x = ans.num[i+j-1]/10; 61 ans.num[i+j-1] %= 10; 62 } 63 ans.num[b.len+i] += x;x = 0; 64 } 65 while(!ans.num[len]) len --; 66 ans.len = len; 67 return ans; 68 } 69 70 bign operator + (bign a,bign b) 71 { 72 ans.clear(); 73 int len = MAX(a.len,b.len)+1; 74 int x = 0; 75 for(register int i = 1;i <= len;++ i) 76 { 77 ans.num[i] = a.num[i]+b.num[i]+x; 78 x = ans.num[i]/10; 79 ans.num[i] %= 10; 80 } 81 if(!ans.num[len]) len --; 82 ans.len = len; 83 return ans; 84 } 85 86 inline void update() 87 { 88 tmp.clear(); 89 for(register int i = 1;i <= n;++ i) 90 for(register int j = 1;j <= m;++ j) 91 f[i][j].clear(); 92 } 93 94 inline bign change(int a) 95 {//把int变量转换为大整数 96 ans.clear(); 97 int len = 0; 98 while(a) 99 { 100 ans.num[++len] = a%10; 101 a /= 10; 102 } 103 ans.len = len; 104 return ans; 105 } 106 107 inline void out(bign a) 108 { 109 int len = a.len; 110 if(!len) puts("0"); 111 else 112 for(register int i = len;i >= 1;-- i) 113 printf("%d",a.num[i]); 114 puts(""); 115 } 116 117 inline void init() 118 {//预处理2的n次方 119 note[0].len = 1,note[0].num[1] = 1; 120 note[1].len = 1,note[1].num[1] = 2; 121 for(register int i = 2;i <= m;++ i) 122 { 123 note[i] = note[i-1]*note[1]; 124 // out(note[i]); 125 } 126 } 127 128 int main() 129 { 130 read(n),read(m); 131 for(register int i = 1;i <= n;++ i) 132 for(register int j = 1;j <= m;++ j) 133 read(x),mp[i][j] = change(x); 134 init(); 135 for(int i = 1;i <= n;++ i) 136 { 137 update(); 138 for(register int l = 1;l <= m;++ l) 139 for(register int r = m;r >= l;-- r) 140 f[l][r] = Max(f[l-1][r]+note[l+m-r-1]*mp[i][l-1],f[l][r+1]+note[l+m-r-1]*mp[i][r+1]); 141 for(register int k = 1;k <= m;++ k) 142 //枚举最后一个选取的数字 143 tmp = Max(tmp,f[k][k]+mp[i][k]*note[m]); 144 Ans = Ans + tmp; 145 } 146 out(Ans); 147 return 0; 148 }
时间: 2024-10-04 20:55:23