1166 矩阵取数游戏
- 每一行的取数的策略都是互相独立的,所以只要找到每行取数的方法即可
- 如果数据较小的话,就可以利用记忆化的DP:
设i,j分别为这行的头和尾,那么
dp[i][j] = max(dp[i+1][j] + a[i] * 2的m次方 , dp[i][j] + a[j] * 2 的m次方)
但是发现m最大可能为80,那么2的80次方,无疑是要使用高精度的。
然而在自己的思维区间中总想不出要怎么使用这个高精度,难道要每个dpi,j的值使用一个数组返回,再比较大小??所以还是去看题解了- - 发现了一个特别好的题解,整体思路就是用一个结构体存储2个long long ,当满足大于一个很大的数时则进位,(这个是因为题目要对这个数值进行分析,才能证明这样的方法可以存储答案,不过最后也有微略提示答案的最大值),足以代表这个最优值,重载运算符+,<, *,即可,虽然自己脑海中也有闪过这样的一种的方法,不过马上被否决了。。自己还是太嫩了。
下面贴一份题解代码:#include<stdio.h> typedef long long ll; ll MAX=1000000000000000; struct bignum{ll p1,p2;}; //p1是一个数的左端,p2是一个数的右端 bignum operator+(const bignum a,const bignum b){ bignum c; c.p1=a.p1+b.p1; c.p2=a.p2+b.p2; if(c.p2>=MAX){ c.p2-=MAX; c.p1++; } return c; } int operator<(const bignum a,const bignum b){ if(a.p1<b.p1)return 1; if(a.p1>b.p1)return 0; if(a.p2<b.p2)return 1; return 0; } bignum pow2(int x){ bignum a; a.p1=0; a.p2=1; while(x--)a=a+a; return a; } bignum operator*(const bignum a,const int b){ bignum c; c.p1=a.p1*b; c.p2=a.p2*b; if(c.p2>=MAX){ c.p1+=c.p2/MAX; c.p2%=MAX; } return c; } void write(const bignum a){ if(a.p1) printf("%lld%015lld",a.p1,a.p2); else printf("%lld",a.p2); } bignum max(const bignum a,const bignum b){ return a<b?b:a; } int main(){ int a[85],i,j,n,m; bignum score,f[85][85]; score.p1=0; score.p2=0; scanf("%d%d",&n,&m); while(n--){ for(i=1;i<=m;i++){ scanf("%d",&a[i]); f[i][i]=pow2(m)*a[i]; //最后一个数肯定是第m次取数了 } for(j=1;j<m;j++) //第m - j 次取数 ,也就是对应的段长为2.3.4....m for(i=1;i<=m-j;i++) f[i][i+j]=max(f[i+1][i+j]+pow2(m-j)*a[i],f[i][i+j-1]+pow2(m-j)*a[i+j]); score=score+f[1][m]; } write(score); }
4.保存下来,日后再刷一次看是否可以用这种思维较为顺利地敲出实现代码。