NOIP2007矩阵取数
Posted cdcq(本博客废弃!现用博客:https://www.cn
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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 }
以上是关于NOIP2007矩阵取数的主要内容,如果未能解决你的问题,请参考以下文章
dp+高精度(洛谷1005 矩阵取数游戏NOIP 2007 提高第三题)
P1005 [NOIP2007 提高组] 矩阵取数游戏(区间dp)