[LuoguP1005]矩阵取数游戏 (DP+高精度)
题面
传送门:https://www.luogu.org/problemnew/show/P1005


Solution
我们可以先考虑贪心
我们每一次都选左右两边尽可能小的数,方便大的放在后面
听起来挺OK的
实则并不OK
反例:
3 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2
如果贪心的话,我们会优先把右边那一串2先选了,再去选3和1
但是正确答案显然是先把3和1选了,再去选那一串2
既然贪心不成,我们可以考虑一下DP
然后我们考虑这样一个状态:
f[i][j][k] 表示第i时刻,第j行,左边选到了第k列
因为我们知道了当前时刻和左边选到的列数,右边选到的列数也可以推算出来: m-i+k-1
然后就可以写出来一个比较显然的转移方程:
f[i][j][k]=max(f[i-1][j][k-1]+2^i*num[j][k-1],f[i-1][j][k]+2^i*num[j][m-i+k])
也就是第i时刻是选最左边的还是选右边的
这样子我们就可以得到 100分 60分
为什么会变成这样的呢?
原因很简单,我们仔细看一下数据范围:80
也就是说数据大小至少会有2^80
显然longlong (Int64)是放不下的
这时候,我们就需要伟大的Int128
你当然可以用stl的int128(虽然考试中不能用)
我们这里选用手写一个高精度类
我们只需要高精乘低精,高精加高精,高精比较大小
再加上若干时间的调试高精
然后就OjbK了
Code
//Luogu P1005 矩阵取数游戏
//DP+高精
//Apr,27th,2018
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
struct Int128
{
int a[50],len;
Int128()
{
memset(a,0,sizeof a);
len=0;
}
void Insert()
{
char c=getchar();
while(!isdigit(c)) c=getchar();
while(isdigit(c)){a[++len]=c-'0';c=getchar();}
int tot=len/2;
for(int i=len;i>tot;i--)swap(a[i],a[len-i+1]);
}
void Print()
{
for(int i=len;i>=1;i--)
printf("%d",a[i]);
}
friend Int128 operator * (Int128 a,int b)
{
Int128 ans=Int128();
ans.len=a.len;
for(int i=1;i<=ans.len;i++)
{
ans.a[i]+=a.a[i]*b;
ans.a[i+1]+=ans.a[i]/10;
ans.a[i]%=10;
if(i==ans.len and ans.a[i+1]!=0)
ans.len++;
}
return ans;
}
friend Int128 operator + (Int128 a,Int128 b)
{
Int128 ans=Int128();
ans.len=max(a.len,b.len);
for(int i=1;i<=ans.len;i++)
{
ans.a[i]+=a.a[i]+b.a[i];
ans.a[i+1]+=ans.a[i]/10;
ans.a[i]%=10;
if(i==ans.len and ans.a[i+1]!=0)
ans.len++;
}
return ans;
}
friend bool operator < (Int128 a,Int128 b)
{
if(a.len<b.len) return true;
if(a.len>b.len) return false;
for(int i=a.len;i>=1;i--)
if(a.a[i]>b.a[i])
return false;
else if(a.a[i]<b.a[i])
return true;
return false;
}
};
const int N=80+10;
Int128 f[2][N][N],POW[N];
int a[N][N];
int n,m;
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&a[i][j]); POW[1].len=1,POW[1].a[1]=2;
for(int i=2;i<=m;i++)
POW[i]=POW[i-1]*2;
for(int i=1;i<=m;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=i+1;k++)
{
if(k>1)
f[i%2][j][k]=f[(i-1)%2][j][k-1]+POW[i]*a[j][k-1];
if(m-i+k-1<m)
f[i%2][j][k]=max(f[i%2][j][k],f[(i-1)%2][j][k]+POW[i]*a[j][m-i+k]);
//f[i%2][j][k].Print();
//cout<<endl;
} Int128 ans=Int128();
for(int i=1;i<=n;i++)
{
Int128 t_ans=Int128();
for(int j=1;j<=m;j++)
t_ans=max(t_ans,f[m%2][i][j]);
ans=ans+t_ans;
} ans.Print();
return 0;
}
[LuoguP1005]矩阵取数游戏 (DP+高精度)的更多相关文章
- [luoguP1005] 矩阵取数游戏(DP + 高精度)
传送门 和奶牛那个题很像,每一行状态互不影响,也就是求 n 遍DP 不过高精度非常恶心,第一次写,调了我一上午. ——代码 #include <cstdio> #include <c ...
- 【Luogu】P1005矩阵取数游戏(高精度+DP)
题目链接 yeah终于过辣! DP,f[i][j]表示每行还剩i到j这个区间的数没取的时候的值.借这个题我也把高精度的短板弥补了一下,以后高精加高精乘应该是没问题了. 哇终于不怂高精了…… 放上代码. ...
- [P1005][NOIP2007] 矩阵取数游戏 (DP+高精)
我不会高精…… 也不会DP…… 这道题即考高精又考DP…… 我要死了 给一个不是高精的代码(当然不能满分) #include<cstdio> #include<iostream> ...
- 1166 矩阵取数游戏[区间dp+高精度]
1166 矩阵取数游戏 2007年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题解 题目描述 Description [ ...
- P1005 矩阵取数游戏 区间dp 高精度
题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n \times mn×m的矩阵,矩阵中的每个元素a_{i,j}ai,j均为非负整数.游戏规则如下: 每次取数时须从每行各取走一个元素,共n ...
- P1005 矩阵取数游戏[区间dp]
题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的\(m*n\)的矩阵,矩阵中的每个元素\(a_{i,j}\)均为非负整数.游戏规则如下: 每次取数时须从每行各取走一个元素,共n个.经过m次后 ...
- 矩阵取数游戏 2007年NOIP全国联赛提高组(dp+高精)
矩阵取数游戏 2007年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题目描述 Description [问题描述]帅帅经常跟 ...
- 矩阵取数游戏 NOIP 2007
2016-05-31 17:26:45 题目链接: NOIP 2007 矩阵取数游戏(Codevs) 题目大意: 给定一个矩阵,每次在每一行的行首或者行尾取一个数乘上2^次数,求取完最多获得的分数 解 ...
- 矩阵取数游戏洛谷p1005
题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数.游戏规则如下: 1.每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 2. ...
随机推荐
- RabbitMQ 3.6.12延迟队列简单示例
简介 延迟队列存储的消息是不希望被消费者立刻拿到的,而是等待特定时间后,消费者才能拿到这个消息进行消费.使用场景比较多,例如订单限时30分钟内支付,否则取消,再如分布式环境中每隔一段时间重复执行某操作 ...
- Markdown 1.0.1
简介 Markdown 是由 John Gruber 于2004年开发一种轻量级标记语言,它是一个面向web作者的 text-to-HTML 转换工具.Markdown编辑器允许您使用纯文本格式编写, ...
- Tomcat 8.5安装
安装 打开Tomcat官网:http://tomcat.apache.org/,下载tar.gz压缩文件,下载后文件名是apache-tomcat- 8.5.23.tar.gz.使用root用户安装, ...
- Hibernate4.3基础知识1
一.Hibernate 开发环境搭建 4.3 1.导包 2.创建hibernate.cfg.xml配置文件 3.创建实体类 4.创建映射文件 实体类名.hbm.xml 配置文件 二.h ...
- GAN训练技巧汇总
GAN自推出以来就以训练困难著称,因为它的训练过程并不是寻找损失函数的最小值,而是寻找生成器和判别器之间的纳什均衡.前者可以直接通过梯度下降来完成,而后者除此之外,还需要其它的训练技巧. 下面对历年关 ...
- 074 01 Android 零基础入门 01 Java基础语法 09 综合案例-数组移位 06 综合案例-数组移位-主方法功能3的实现
074 01 Android 零基础入门 01 Java基础语法 09 综合案例-数组移位 06 综合案例-数组移位-主方法功能3的实现 本文知识点:综合案例-数组移位-主方法功能3的实现 说明:因为 ...
- python双向链表的实现
python双向链表和单链表类似,只不过是增加了一个指向前面一个元素的指针,下面的代码实例了python双向链表的方法 示意图: python双向链表实现代码: # -*- coding: utf-8 ...
- Pock 把 Touch Bar 变成系统中的 Dock 栏
Pock 把 Touch Bar 变成系统中的 Dock 栏 Pock 是一款 macOS App,你可以通过它把 Touch Bar 变成系统中的 Dock 栏,直接用来切换和启动 App,尽享全屏 ...
- Vue结合Django-Rest-Frameword结合实现登录认证(二)
作者:小土豆biubiubiu 博客园:https://www.cnblogs.com/HouJiao/ 掘金:https://juejin.im/user/2436173500265335 微信公众 ...
- lua 1.0 源码分析 -- 1 lua 的虚拟指令
lua的解释器拿到 lua 编写的源码,首先进行解析,就是进行词法分析和语法分析,将源码转换成 lua 的指令集,然后执行这个指令集. lua 源码: function f(val) return v ...