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. ...
随机推荐
- bzoj2555(lct维护sam)
题意: (1):在当前字符串的后面插入一个字符串 (2):询问字符串s在当前字符串中出现了几次?(作为连续子串) 字符串长度<=6e5,询问总长度<=3e6 分析: 考虑建个sam,然后把 ...
- php使用strpos,strstr,strchr注意啦,若是数字查找则会当成ASCII码处理
strpos,strstr,strchr都是查找某字符出现的位置,若未找到,则返回false(判断是===) 如: var_dump(strpos("oa",'97')); var ...
- CSS 居中 可随着浏览器变大变小而居中
关键代码: 外部DIV使用: text-align:center; 内部DIV使用: margin-left:auto;margin-right:auto 例: <div style=" ...
- 【mac】mac上使用brew 安装速度慢/每次使用brew 都会卡在updating homebrew不动/更换homebrew的镜像源
有没有出现一下这样的情况: 如果有,请继续往下走 1.打开mac的命令窗口,键入如下命令 cd /usr/local/Homebrew 2.更换homebrew的默认源[更换为中科大的镜像源] git ...
- 【Todo】【读书笔记】Career Cup 150笔记
下载了第五版:/Users/baidu/Documents/Data/Interview/算法与数据结构/<CareerCup+Top+150+Questions+5th.pdf> 参考这 ...
- 数据库系统学习(九)-嵌入式SQL语言之基本技巧
第九讲 嵌入式SQL语言之基本技巧 901 什么是嵌入式SQL语言 交互式SQL语言的局限性 嵌入式SQL语言 交互式和嵌入式语言的对比 高级语言中使用嵌入式语言需要解决的问题 902 程序与数据库连 ...
- centos 7 -- Disk Requirements: At least 134MB more space needed on the / filesystem.
用了幾年的centos7,今天執行yum update時,彈出一行有錯誤的提示:Disk Requirements: At least 134MB more space needed on the ...
- People seldom do what they believe in. They do what is convenient, then repent.
People seldom do what they believe in. They do what is convenient, then repent. 人们很少真正实践他们的理想.他们只做比较 ...
- GridView的经常使用属性
1.android:numColumns="auto_fit" //GridView的列数设置为自己主动 2.android:columnWidth="90dp &q ...
- SAE云平台的使用
参考文章:http://www.cnblogs.com/luyangsblog/p/3956135.html Web开发从零单排之一:在新浪云平台SAE上开发一个htm ...