题目描述

帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素a(i,j)均为非负整数。游戏规则如下:

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

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

输入输出格式

输入格式:

输入文件包括n+1行:

第1行为两个用空格隔开的整数n和m。

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

输出格式:

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

输入输出样例

输入样例#1:

2 3
1 2 3
3 4 2

输出样例#1:

82

说明

NOIP 2007 提高第三题

数据范围:

60%的数据满足:1≤n,m≤30,答案不超过10^16

100%的数据满足:1≤n,m≤80,0≤a(i,j)≤1000

分析:

  

首先我们可以看此题的数据范围,显然要么是高精,要么是某种玄学优化,这里主要介绍高精,玄学优化就不讲了。
接下来看题目:易证总得分为每一行m次取数后每行的最优解的总和。证明因为太简单了,博主懒得写~
所以我们只需要计算出每一行的m次取数后的最优解即可。

对于最优解,我们考虑使用dp解法:f[t][k][i][j]表示第k行第i次取到了第j个数时的最优解,当t=0时,表示第k个数是从行首取到,t=1时反之。

(其中1<=k<=n,1<=i,j<=m,0<=t<=1)

很显然,当i<j<m-i+1时,无法取到第k个数,因为全部从行首取只能取到第i个,全部从行尾取只能取到第m-i+1个,所以我们将这一部分数组赋值为0。

接下来我们便可以得到转移方程:f[0][k][i][j]=max(f[0][k][i-1][j-1],f[1][k][i-1][m-(i-j)+1])+2^i*a[k][j]

               f[1][k][i][j]=max(f[1][k][i-1][j+1],f[0][k][i-1][i-(m-j+1)])+2^i*a[k][j]


转移方程解释:每一行max的第一个项为上一次取了行首(行尾)后,这一次第j个数变成了行首(行尾),每一行max的第二个项为上一次去了行首(行尾),这一次取的是行尾(行首),则可推出若上一次取的行首(行尾)的位置,故有此转移方程。

到这里我们已经完成了这个问题的大部分,但是仍然存在一个问题:

如果以这样的dp来算空间复杂度的话,则空间复杂度为2(t)*80(k)*80(i)*80(j)*大整数位数,若大整数位数过大,则很容易爆空间(空间限制128M),位数过小又容易溢出,所以我们考虑使用压位高精压缩空间。(当然也可以用一些玄学优化,比如开两个longlong存大整数之类的)

下面只需通过压位高精来完成这个dp了,不详细解释,见代码:

#include <cstdio>
#include <cstring>
#include <iostream>
using namespace std;
struct dzs{int ws,li[20];
};//高精度结构体
int a[81][81],n,m;
dzs f[2][81][81][81],er[81],an,ans,pss1,pss2;
dzs gjc(int p1,dzs p2){   //高精乘单精 for(int i=1;i<=p2.ws;i++)p2.li[i]*=p1;for(int i=1;i<=p2.ws+5;i++){if(i>p2.ws&&p2.li[i]!=0)p2.ws=i;if(p2.li[i]>9999)p2.li[i+1]+=p2.li[i]/10000,p2.li[i]%=10000;}return p2;
}
dzs gjj(dzs p1,dzs p2){   //高精加dzs p3;memset(p3.li,0,sizeof(p3.li));p3.ws=1;for(int i=1;i<=max(p1.ws,p2.ws);i++)p3.li[i]=p2.li[i]+p1.li[i];for(int i=1;i<=p2.ws+5;i++){if(i>p3.ws&&p3.li[i]!=0)p3.ws=i;if(p3.li[i]>9999)p3.li[i+1]+=p3.li[i]/10000,p3.li[i]%=10000;}return p3;
}
dzs maxd(dzs p1,dzs p2){  //取大数 if(p1.ws>p2.ws)return p1;if(p2.ws>p1.ws)return p2;for(int i=p1.ws;i>=1;i--){if(p1.li[i]>p2.li[i])return p1;if(p1.li[i]<p2.li[i])return p2;}return p1;
}
int print(dzs p1){for(int i=p1.ws;i>=1;i--){if(i==p1.ws){cout<<p1.li[i];continue;}if(p1.li[i]<10)cout<<"000";else if(p1.li[i]<100)cout<<"00";else if(p1.li[i]<1000)cout<<"0";cout<<p1.li[i];}
}//输出高精度整数
int main(){cin>>n>>m;for(int i=1;i<=n;i++)for(int j=1;j<=m;j++)cin>>a[i][j];er[1].li[1]=2;er[1].ws=1;for(int i=2;i<=m;i++){er[i]=gjc(2,er[i-1]);}//计算2^ifor(int k=1;k<=n;k++)for(int i=1;i<=m;i++){ for(int j=1;j<=i;j++){f[0][k][i][j]=gjj(maxd(f[0][k][i-1][j-1],f[1][k][i-1][m-(i-j)+1]),gjc(a[k][j],er[i]));}for(int j=m-i+1;j<=m;j++){f[1][k][i][j]=gjj(maxd(f[1][k][i-1][j+1],f[0][k][i-1][i-(m-j+1)]),gjc(a[k][j],er[i]));}}memset(ans.li,0,sizeof(ans.li));ans.ws=1;for(int k=1;k<=n;k++){an.ws=1;memset(an.li,0,sizeof(an.li));for(int i=1;i<=m;i++){an=maxd(an,f[0][k][m][i]);an=maxd(an,f[1][k][m][i]);}ans=gjj(ans,an);}print(ans);cout<<endl;return 0;
}

转载于:https://www.cnblogs.com/huangxuanao/p/9795570.html

NOIP2007 提高组【矩阵取数游戏】题解相关推荐

  1. [NOIP2007 提高组] 矩阵取数游戏

    首先这个题的转移方程楼下的都说过了,就是在每行上的[i,j]区间的最大值 dp[i][j]=max{dp[i+1][j]+2^(m-(j-i))×v[i],dp[i][j-1]+2^(m-(j-i)) ...

  2. 【区间DP+高精】codevs1166 矩阵取数游戏题解

    转自: [ametake版权所有]http://blog.csdn.net/ametake欢迎来看 http://blog.csdn.net/ametake/article/details/47664 ...

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

    题目来自NOIP2007TG3 如果在考场上我现在已经歇菜了吧 今天一整天的时间全部投在这道题上,收获不小. 先上题目 题目描述 Description [问题描述] 帅帅经常跟同学玩一个矩阵取数游戏 ...

  4. 【NOIP2007提高组】矩阵取数游戏

    题目背景 NOIP2007提高组试题3. 题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的 n*m 的矩阵,矩阵中的每个元素 aij 均为非负整数.游戏规则如下: 1.每次取数时须从每行各取 ...

  5. 矩阵游戏java_矩阵取数游戏JAVA题解

    话不多说,先上题目: 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的nm的矩阵,矩阵中的每个元素aij均为非负整数.游戏规则如下: {C}1. 每次取数时须从每行各取走一个元素,共n个.m次后取完矩 ...

  6. 洛谷1005 【NOIP2007】矩阵取数游戏

    问题描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数.游戏规则如下: 1.每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 2. ...

  7. 【codevs1166】【noip07TG】矩阵取数游戏,新的开始

    1166 矩阵取数游戏 2007年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题解 题目描述 Description [问题描述] 帅帅经 ...

  8. 【每日一题】7月10日精讲—矩阵取数游戏

    来源:牛客网: 文章目录 题目描述 题解: 代码: 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 262144K,其他语言524288K 64bit IO Format: %lld ...

  9. 【每日DP】day 10、P1005 矩阵取数游戏【区间DP+高精(python)】难度⭐⭐⭐★

    P1005 矩阵取数游戏 输入 2 3 1 2 3 3 4 2 输出 82 说明/提示 NOIP 2007 提高第三题. 数据范围: 60%60\%60% 的数据满足:1≤n,m≤301\le n,m ...

最新文章

  1. Google Map API 学习六-设置infoWindow的长宽
  2. angular2 安装
  3. Spring MVC讲解
  4. [C++] 用Xcode来写C++程序[6] Name visibility
  5. 有关 php __autoload 自动加载类函数的用法
  6. java 简单类继承
  7. python中int什么意思_python3中int(整型)的使用教程
  8. ​突破数据存储瓶颈,Aibee实现场景化AI的有效落地
  9. 单片机编程软件IAR和烧写软件SmartRF安装教程(超详细)
  10. Code Review : Review Board + Svn
  11. Excel-几行几行进行转置
  12. python是高级语言还是低级语言_高级与低级编程语言的解释,哪一种更容易上手?...
  13. 中学计算机课小课题,信息技术小课题研究题目大全
  14. L5 Limits and Continuity
  15. 什么是360度全景图,360度全景图有什么用
  16. CF1428F Fruit Sequences
  17. 扒一扒迅雷的代码结构
  18. 加州房价预测数据预处理
  19. 使用google map v3 api 开发地图服务
  20. ThreadX学习(2)——线程

热门文章

  1. Python 之 处理 Excel 数据(5) —— 更新指定单元格的值
  2. 达人评测 i5 13500h和i9 12900h选哪个好 酷睿i513500h和i912900h差距
  3. 阅读速度慢怎么办?提高阅读速度的8个技巧
  4. 电动汽车平均每天起火近10辆,再次强调能买燃油车就别买电动汽车
  5. 真正意义上的数字零售,最为重要的一点就是要回归零售本身
  6. 2021年全球V型温度计行业调研及趋势分析报告
  7. java 视频无损压缩_ffmpeg 4:3视频无损压制16:9
  8. CTF学习-栅栏密码
  9. NKUOJ 1004题 糖葫芦游戏
  10. Unity Text 实现文本上下标功能