NOIP2007 矩阵取数游戏(区间DP)
这道题第一眼看上去可能让人以为是贪心……不过贪心并不行,因为每次的操作是有2的幂次方的权值的。这样的话直接每次贪心最小的就目光短浅。所以那我们自然想到了DP。
据说这是一道很正常的区间DP?
区间DP的基本思想,就是先处理出小区间的最优解,再由多个小区间合并成一个大区间。
不过这道题的想法略微有些不同。首先从题目描述上来看,每行的取数是独立的,对于每一行我们来分析一下。
首先,因为题目中说只能取一行元素当前的首个元素或者末尾元素。既然如此,我们假设dp[i][j]表示选取区间i~j所能获得的最大值。
这样的话,dp[i][j]就只能从两方面转移过来。一是dp[i+1][j],二是dp[i][j-1].这样的话,我们考虑一下转移时候的状态。因为每次转移所获的的分数是当前选取的数值乘以2^选举的次数,所以我们可以这么想,对于一个内部的区间,它在被转移的时候,本身是要被*2的。之后这种状态就会被继续跟随着*2,所以选到最后必然是符合题意的。
所以说DP的方程就是dp[i][j] = min(dp[i+1][j]*2 + a[i] * 2,dp[i][j-1]*2 + a[j]*2);
DP方程说完了,之后说该怎么DP。我们知道区间DP的思想是先算小区间,之后合并成大区间,所以我们可以从0~n-1枚举区间长度,之后枚举区间的左右端点进行转移。
还有就是这道题要使用高精度……不过可以选择自己写一个高精乘,高精加,和高精度比较的struct,直接封装起来。这样就可以了。
看一下代码(因为高精模板是抄的……高精减可以忽略……)
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define rep(i,a,n) for(ll i = a;i <= n;i++)
#define per(i,n,a) for(ll i = n;i >= a;i--)
#define enter putchar('\n') using namespace std;
const int M = ;
typedef long long ll; int read()
{
int ans = ,op = ;
char ch = getchar();
while(ch < '' || ch > '')
{
if(ch == '-') op = -;
ch = getchar();
}
while(ch >= '' && ch <= '')
{
ans *= ;
ans += ch - '';
ch = getchar();
}
return ans * op;
} struct big
{
int len,num[];
big()
{
len = ;
memset(num,,sizeof(num));
}
big(int p)
{
len = ;
while(p) num[++len] = p % ,p /= ;
}
void init(int p)
{
len = ;
while(p) num[++len] = p % ,p /= ;
}
big operator + (const big &g) const
{
big ans;
int s = max(len,g.len);
ans.len = s;
rep(i,,s)
{
ans.num[i] += num[i] + g.num[i];
if(ans.num[i] >= ) ans.num[i] -= ,ans.num[i+]++;
}
if(ans.num[s+]) ans.len++;
return ans;
}
big operator - (const big &g) const
{
big ans;
int s = max(len,g.len);
ans.len = s;
rep(i,,s) ans.num[i] = num[i] - g.num[i];
rep(i,,s) if(ans.num[i] < ) ans.num[i+]--,ans.num[i] += ;
if(ans.num[s+] != ) ans.len++;
return ans;
}
big operator * (const big &g) const
{
big ans;
int s1 = len,s2 = g.len;
rep(i,,s1)
rep(j,,s2) ans.num[i+j-] += num[i] * g.num[j];
int s = s1 + s2 - ,k = ;
while(ans.num[k] || k <= s)
{
ans.num[k+] += ans.num[k] / ;
ans.num[k] = ans.num[k] % ;
k++;
}
if(!ans.num[k]) k--;
ans.len = k;
return ans;
}
friend big bmax(const big &f,const big &g)
{
if(f.len < g.len) return g;
else if(f.len > g.len) return f;
else
{
per(i,f.len,)
{
if(f.num[i] < g.num[i]) return g;
else if(f.num[i] > g.num[i]) return f;
}
}
return f;
}
void out()
{
if(!len) printf("0\n");
per(i,len,) printf("%d",num[i]);enter;
}
};
big a,b,c,f[][],dp[][][],ans,pow2[],now; int n,m; int main()
{
n = read(),m = read();
pow2[].init();
rep(i,,m) pow2[i] = pow2[i-] * pow2[];
rep(i,,n)
rep(j,,m) f[i][j].init(read());
rep(i,,n)
{
rep(p,,m)
rep(q,,m-p)
{
dp[i][q][p+q] = bmax((dp[i][q+][p+q] * pow2[] + pow2[] * f[i][q]),(dp[i][q][p+q-] * pow2[] + pow2[] * f[i][p+q]));//注意第一维只是起计数作用,无实际意义。
// now = dp[i][q][p+q],now.out();
}
ans = ans + dp[i][][m];
}
ans.out();
return ;
}
NOIP2007 矩阵取数游戏(区间DP)的更多相关文章
- 1166 矩阵取数游戏[区间dp+高精度]
1166 矩阵取数游戏 2007年NOIP全国联赛提高组 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 黄金 Gold 题解 题目描述 Description [ ...
- P1005 矩阵取数游戏[区间dp]
题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的\(m*n\)的矩阵,矩阵中的每个元素\(a_{i,j}\)均为非负整数.游戏规则如下: 每次取数时须从每行各取走一个元素,共n个.经过m次后 ...
- P1005 矩阵取数游戏 区间dp 高精度
题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n \times mn×m的矩阵,矩阵中的每个元素a_{i,j}ai,j均为非负整数.游戏规则如下: 每次取数时须从每行各取走一个元素,共n ...
- NOIP2007 矩阵取数游戏
题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数.游戏规则如下: 1.每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 2. ...
- [P1005][NOIP2007] 矩阵取数游戏 (DP+高精)
我不会高精…… 也不会DP…… 这道题即考高精又考DP…… 我要死了 给一个不是高精的代码(当然不能满分) #include<cstdio> #include<iostream> ...
- [luoguP1005] 矩阵取数游戏(DP + 高精度)
传送门 和奶牛那个题很像,每一行状态互不影响,也就是求 n 遍DP 不过高精度非常恶心,第一次写,调了我一上午. ——代码 #include <cstdio> #include <c ...
- [NOIP2007] 提高组 洛谷P1005 矩阵取数游戏
题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数.游戏规则如下: 1.每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 2. ...
- NOIP2007矩阵取数[DP|高精度]
题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数.游戏规则如下: 1.每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 2. ...
- 洛谷1005 【NOIP2007】矩阵取数游戏
问题描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数.游戏规则如下: 1.每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 2. ...
随机推荐
- CodeForces - 813C The Tag Game (树的dfs遍历)
[传送门]http://codeforces.com/problemset/problem/813/C [题目大意]两个人玩游戏,一个人跑一个人追,轮流决策,可以走也可以不走.给你一棵树,想要从某个结 ...
- Easy sssp(spfa)(负环)
vijos 1053 Easy sssp 方法:用spfa判断是否存在负环 描述 输入数据给出一个有N(2 <= N <= 1,000)个节点,M(M <= 100,00 ...
- mybatis注解@selectKey对于db2数据库的使用
在新增时返回当前新增的主键. 数据库:DB2 用的是mybatis的@selectKey 代码: @InsertProvider(type = Test.class,method="inse ...
- Chrome常用URL命令(伪URL)
在Chrome地址栏输入chrome://chrome-urls/可以看到所有的Chrome支持的伪RUL 1.chrome://accessibility/ 可达性分析,默认是关闭的,点击acces ...
- vim中末行去掉^M
在Ubuntu系统中打开文件,发现文件中每一个末行都有^M,我们要做的是知道这一个无关的字符是什么作用,然后删除掉这一个无关的字符. 工具/原料 ubuntu操作系统 Vim编辑器 方法/步骤 ...
- 子组件跟随父组件re-render
想象一下这种场景,一个父组件下面一大堆子组件.然后呢,这个父组件re-render.是不是下面的子组件都得跟着re-render.可是很多子组件里面是冤枉的啊!!很多子组件的props 和 state ...
- docker compose环境搭建
概述 Docker Compose提供一个简单的基于YAML配置语言.用于描写叙述和组装多容器的分布式应用. 使用docker定义和执行复杂的应用.使用compose,能够在一个文件中,定义多容器的应 ...
- centos7+php7 swoole 安装
下载 swoole 首先下载swoole的源码包,这个操作很简单,没有太多说的. wget -c https://github.com/swoole/swoole-src/archive/v2.0.6 ...
- coco2d-x 3.0游戏实例学习笔记 《跑酷》 第二步---游戏界面&全新的3.0物理世界
说明:这里是借鉴:晓风残月前辈的博客,他是将泰然网的跑酷教程.用cocos2d-x 2.X 版本号重写的,眼下我正在学习cocos2d-X3.0 于是就用cocos2d-X 3.0重写.并做相关笔记 ...
- 理解和使用WPF 验证机制
博客 学院 下载 更多 写博客 发布Chat 登录注册 理解和使用WPF 验证机制 原创 2013年06月20日 11:15:37 7404 首先建立一个demo用以学习和实验WPF Data Val ...