首页 > 代码库 > 【NOIP2007】矩阵取数
【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;傻逼了qaq15 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];第二次傻逼qaq24 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】矩阵取数