洛谷 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 }
时间: 2024-10-04 20:55:23

洛谷 P1005 矩阵取数游戏 题解的相关文章

洛谷P1005 矩阵取数游戏

P1005 矩阵取数游戏 题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数.游戏规则如下: 1.每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 2.每次取走的各个元素只能是该元素所在行的行首或行尾: 3.每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值*2^i,其中i表示第i次取数(从1开始编号): 4.游戏结束总得分为m次取数得分之和. 帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出

洛谷 P1005 矩阵取数游戏

题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数.游戏规则如下: 1.每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 2.每次取走的各个元素只能是该元素所在行的行首或行尾: 3.每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值*2^i,其中i表示第i次取数(从1开始编号): 4.游戏结束总得分为m次取数得分之和. 帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分. 输入输

dp+高精度(洛谷1005 矩阵取数游戏NOIP 2007 提高第三题)

帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数.游戏规则如下: 1.每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 2.每次取走的各个元素只能是该元素所在行的行首或行尾: 3.每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值*2^i,其中i表示第i次取数(从1开始编号): 4.游戏结束总得分为m次取数得分之和. 帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分. 输入格式: 输入

P1005 矩阵取数游戏

P1005 矩阵取数游戏 题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数.游戏规则如下: 1.每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 2.每次取走的各个元素只能是该元素所在行的行首或行尾: 3.每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值*2^i,其中i表示第i次取数(从1开始编号): 4.游戏结束总得分为m次取数得分之和. 帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出

Noip2007矩阵取数游戏题解

题目描述 Description [问题描述] 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n?m的矩阵,矩阵中的每个元素ai,j均 为非负整数.游戏规则如下: 每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 每次取走的各个元素只能是该元素所在行的行首或行尾: 每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分=被取走的元素值?2i, 其中i表示第i 次取数(从1 开始编号): 游戏结束总得分为m次取数得分之和. 帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出

P1005矩阵取数游戏

题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数.游戏规则如下: 1.每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 2.每次取走的各个元素只能是该元素所在行的行首或行尾: 3.每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值*2^i,其中i表示第i次取数(从1开始编号): 4.游戏结束总得分为m次取数得分之和. 帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出取数后的最大得分. 输入输

【日常学习】【区间DP+高精】codevs1166 矩阵取数游戏题解

题目来自NOIP2007TG3 如果在考场上我现在已经歇菜了吧 今天一整天的时间全部投在这道题上,收获不小. 先上题目 题目描述 Description [问题描述] 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m 的矩阵,矩阵中的每个元素aij均 为非负整数.游戏规则如下: 1. 每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 2. 每次取走的各个元素只能是该元素所在行的行首或行尾: 3. 每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分= 被取走的元素

18.7.27 luogu P1005 矩阵取数游戏

题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的 n \times mn×m 的矩阵,矩阵中的每个元素 a_{i,j}ai,j? 均为非负整数.游戏规则如下: 每次取数时须从每行各取走一个元素,共 nn 个.经过 mm 次后取完矩阵内所有元素: 每次取走的各个元素只能是该元素所在行的行首或行尾: 每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值 \times 2^i×2i ,其中 ii 表示第 ii 次取数(从 11 开始编号): 游戏结束总得分为 mm

luogu P1005 矩阵取数游戏 区间DP

每一行是独立的,分开处理即可. dp[i][j]表示[i,j]这一段,取完的最大收益.转移很显然,dp[i][j] = max(dp[i + 1][j] + 2^(m - (j - l)) * mp[t][i],dp[i][j - 1] + 2^(m - (j - l)) * mp[t][j]) 不想写高精度,python水一发. 1 n,m = map(int,input().split()) 2 res = 0 3 mp = [[0 for i in range(0,80,1)] for i