【NOIP2007】矩阵取数

因为傻逼写错高精度搞了一下午浪费好多时间,好想哭qaq

原题:

帅帅经常更同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij据为非负整数。游戏规则如下:
  1. 每次取数时须从每行各取走一个元素,共n个。m次后取完矩阵所有的元素;
  2. 每次取走的各个元素只能是该元素所在行的行首或行尾;
  3. 每次取数都有一个得分值,为每行取数的得分之和;每行取数的得分 = 被取走的元素值*2^i,其中i表示第i次取数(从1开始编号);
  4. 游戏结束总得分为m次取数得分之和。

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

1<=n, m<=80,0<=a[i][j]<=1000

首先每一行怎么取互不影响,就可以分开来搞,最后加到一起,下面说的f,a都是某一行里的

然后每一行中区间DP,f[i][j]表示i到j这个区间最大值多少,f[i][j]=max(f[i+1][j]+a[i],f[i][j-1]+a[j])*2

在求f[i][j]的时候直接在后面*2,这样子就不用计算2^i的高精度运算

高精度傻逼了一下午,能力会随着时间的推移降低

记录傻逼的高精度错误:
//for(int i=1;i<=x[0];i++)  x[i]=f[_left][_right][i]+z;高精度+单精度不是这么写的qaq

正确做法:x[1]+=z

while(x[x[0]+1]){  x[0]++;  x[x[0]+1]+=x[x[0]]/ss,x[x[0]]%=ss;}//如果没有每次都清空的话,会因为上一次遗留下来的数继续往后推

//for(int i=1;i<=nleft[0];i++)if(nleft[i]!=nright[i])  return nleft[i]>nright[i];高精度比较应该先比高位qaq

代码:

 1 //因为高精度傻逼了搞了一下午,好想哭qaq
 2 #include<iostream>
 3 #include<cstdio>
 4 #include<algorithm>
 5 #include<cstring>
 6 using namespace std;
 7 const int ss=10000;
 8 int m,n,a[110][110];
 9 int ans[11000];
10 int f[90][90][1100];
11 int nleft[1100],nright[1100];
12 void getn(int *x,int _left,int _right,int z){
13     x[0]=f[_left][_right][0];
14     //for(int i=1;i<=x[0];i++)  x[i]=f[_left][_right][i]+z;傻逼了qaq
15     for(int i=1;i<=x[0];i++)  x[i]=f[_left][_right][i];
16     x[1]+=z;
17     for(int i=1;i<=x[0];i++)  x[i+1]+=x[i]/ss,x[i]%=ss;
18     while(x[x[0]+1]){  x[0]++;  x[x[0]+1]+=x[x[0]]/ss,x[x[0]]%=ss;}//注意这里,如果没有每次都清空的话,会因为上一次遗留下来的数继续往后推
19 }
20 bool getmax(){
21     if(nleft[0]>nright[0])  return true;
22     if(nleft[0]<nright[0])  return false;
23     //for(int i=1;i<=nleft[0];i++)if(nleft[i]!=nright[i])  return nleft[i]>nright[i];第二次傻逼qaq
24     for(int i=nleft[0];i>=1;i--)if(nleft[i]!=nright[i])  return nleft[i]>nright[i];
25     return true;
26 }
27 void fan(int *x){
28     for(int i=1;i<=x[0];i++)  x[i]<<=1;
29     for(int i=1;i<=x[0];i++)  x[i+1]+=x[i]/ss,x[i]%=ss;
30     while(x[x[0]+1]){  x[0]++;  x[x[0]+1]+=x[x[0]]/ss,x[x[0]]%=ss;}
31 }
32 void jia(int *x,int *y){
33     x[0]=max(x[0],y[0]);
34     for(int i=1;i<=x[0];i++)  x[i]+=y[i];
35     for(int i=1;i<=x[0];i++)  x[i+1]+=x[i]/ss,x[i]%=ss;
36     while(x[x[0]+1]){  x[0]++;  x[x[0]+1]+=x[x[0]]/ss,x[x[0]]%=ss;}
37 }
38 void copy(int *x,int *y){  y[0]=x[0];  for(int i=1;i<=x[0];i++)  y[i]=x[i];}
39 int main(){//freopen("ddd.in","r",stdin);
40     //freopen("ddd.out","w",stdout);
41     cin>>m>>n;
42     for(int i=1;i<=m;i++)  for(int j=1;j<=n;j++)  scanf("%d",&a[i][j]);
43     for(int k=1;k<=m;k++){
44         memset(f,0,sizeof(f));
45         for(int i=1;i<=n;i++)  f[i][i][f[i][i][0]=1]=a[k][i]*2;//因为输入数据保证a[i][j]<=1000所以直接塞进去就行了
46         for(int l=2;l<=n;l++)
47             for(int i=1,j=i+l-1;j<=n;i++,j++){
48                 memset(nleft,0,sizeof(nleft)),memset(nright,0,sizeof(nright));
49                 getn(nleft,i+1,j,a[k][i]),getn(nright,i,j-1,a[k][j]);
50                 //cout<<nleft[0]<<endl;
51                 copy((getmax() ? nleft : nright),f[i][j]);
52                 fan(f[i][j]);
53                 /*cout<<f[i][j][f[i][j][0]];
54                 for(int t=f[i][j][0]-1;t>=1;t--)  printf("%04d",f[i][j][t]);
55                 cout<<endl;*/
56             }
57         jia(ans,f[1][n]);
58     }
59     cout<<ans[ans[0]];
60     for(int i=ans[0]-1;i>=1;i--)  printf("%04d",ans[i]);
61     cout<<endl;
62     return 0;
63 }

时间: 2024-10-09 14:00:35

【NOIP2007】矩阵取数的相关文章

NOIP2007 矩阵取数游戏

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

NOIP2007矩阵取数游戏

眼看就要刷完NOIP2007了,然而我忽然想放弃了,咱家图论崩的一B,最后一题可能要推迟放出了,咱们返回正题:矩阵取数 题目简述:给你一个n*m的矩阵,每次从每一行的行头或行末取出一个数,这个数乘上2 ^ i (i 是 第几次取数) 加到answer中,求answer的最大值 你是不是有一种贪心的冲动?我就无脑写了一个,对于每次的两个选择中取较小的数,加到answer中,然而三组样例只能过一组. 贪心是不可行的,证明呢,由程序完成.让我们来想想正解应该怎么写吧,具体的分析过后我们可以发现一个隐含

NOIP2007矩阵取数[DP|高精度]

题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的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次取数得分之和. 帅帅想请你帮忙写一个程序,对于任意矩阵,可以求出

矩阵取数游戏 NOIP 2007

2016-05-31 17:26:45 题目链接: NOIP 2007 矩阵取数游戏(Codevs) 题目大意: 给定一个矩阵,每次在每一行的行首或者行尾取一个数乘上2^次数,求取完最多获得的分数 解法: 动态规划 DP[i][j]表示当前行i位置到j位置获得的最大分数 转移方程: DP[i][j]=max(DP[i+1][j]+a[i]*2^x,DP[i][j-1]+a[i]*2^x); 需要注意的地方: 1.M和N给的范围略坑啊,2^80只有悄悄不说话了,所以直接上了100000的压位,感觉

51nod 1084 矩阵取数问题 V2

1084 矩阵取数问题 V2 基准时间限制:2 秒 空间限制:131072 KB 一个M*N矩阵中有不同的正整数,经过这个格子,就能获得相应价值的奖励,先从左上走到右下,再从右下走到左上.第1遍时只能向下和向右走,第2遍时只能向上和向左走.两次如果经过同一个格子,则该格子的奖励只计算一次,求能够获得的最大价值. 例如:3 * 3的方格. 1 3 3 2 1 3 2 2 1 能够获得的最大价值为:17.1 -> 3 -> 3 -> 3 -> 1 -> 2 -> 2 -&g

1083 矩阵取数问题

1083 矩阵取数问题 基准时间限制:1 秒 空间限制:131072 KB 分值: 5 难度:1级算法题 收藏 关注 一个N*N矩阵中有不同的正整数,经过这个格子,就能获得相应价值的奖励,从左上走到右下,只能向下向右走,求能够获得的最大价值. 例如:3 * 3的方格. 1 3 3 2 1 3 2 2 1 能够获得的最大价值为:11. Input 第1行:N,N为矩阵的大小.(2 <= N <= 500) 第2 - N + 1行:每行N个数,中间用空格隔开,对应格子中奖励的价值.(1 <=

51Nod 1083 矩阵取数问题(矩阵取数dp,基础题)

1083 矩阵取数问题 基准时间限制:1 秒 空间限制:131072 KB 分值: 5 难度:1级算法题 一个N*N矩阵中有不同的正整数,经过这个格子,就能获得相应价值的奖励,从左上走到右下,只能向下向右走,求能够获得的最大价值. 例如:3 * 3的方格. 1 3 3 2 1 3 2 2 1 能够获得的最大价值为:11. Input 第1行:N,N为矩阵的大小.(2 <= N <= 500) 第2 - N + 1行:每行N个数,中间用空格隔开,对应格子中奖励的价值.(1 <= N[i] 

TYVJ 矩阵取数 Label:高精度+dp

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