洛谷 P1005 矩阵取数游戏 题解

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了洛谷 P1005 矩阵取数游戏 题解相关的知识,希望对你有一定的参考价值。

此文为博主原创题解,转载时请通知博主,并把原文链接放在正文醒目位置。

题目链接: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 }

 

以上是关于洛谷 P1005 矩阵取数游戏 题解的主要内容,如果未能解决你的问题,请参考以下文章

洛谷P1005 矩阵取数游戏

洛谷 P1005 矩阵取数游戏

洛谷 P1005 矩阵取数游戏

矩阵取数游戏洛谷p1005

P1005 矩阵取数游戏

P1005矩阵取数游戏