状态转移方程可以直接用dp[i][j]=max(dp[i+1,j]+a[i],dp[i,j-1]+a[j])*(2^k)),但是还要算2^k次方,可以先用数组储存2的方幂,但不可避免高精度乘法,如果只是*2的话可以用加法代替
逆向思考,自内而外,用f[i,j]表示从i取到j的最大值,状态转移方程便为f[i,j]:=max(f[i+1,j]+a[i],f[i,j-1]+a[j])*2 ,相当于每到下一层都把上一层乘了2,越在内层,乘2的次数越多,这样我们就免于高精度乘法了
简略代码如下:
struct bigint {int a[40];}; int m,n; bigint a[81],res,f[81][81],k1,k2; bigint add(bigint k,bigint l) { bigint j; memset(j.a, 0, sizeof(j.a)); for(int i=1;i<=k.a[0]||i<=l.a[0];i++) j.a[i]=k.a[i]+l.a[i]; j.a[0]=k.a[0]>l.a[0]?k.a[0]:l.a[0]; for(int i = 1; i <= j.a[0]; i++){ j.a[i+1]+=j.a[i]/10; j.a[i]%=10; } if(j.a[j.a[0]+1]>0) j.a[0]++; return j; } //////////////////////////////////////////////////////////// bigint cmp(bigint k,bigint l) { if(k.a[0]>l.a[0]) return k; if(k.a[0]<l.a[0]) return l; if(k.a[0]==l.a[0]) for(int i=k.a[0];i>=1;i--){ if(k.a[i]>l.a[i]) return k; if(k.a[i]<l.a[i]) return l; } return l; } ////////////////////////////////////////////////////////////// void init() { memset(a,0,sizeof(a)); for(int i=1;i<=m;i++){ scanf("%d",&a[i].a[1]); a[i].a[0]=1; while(a[i].a[a[i].a[0]]>=10) {//a[0]表示a的位数,将输入的存在[1]中的数分散到a[1,2..]中去 a[i].a[a[i].a[0]+1]=a[i].a[a[i].a[0]]/10; a[i].a[a[i].a[0]]%=10; a[i].a[0]++; } } } ///////////////////////////////////////////////////////////// void solve() { memset(f,0,sizeof(f)); for(int i=1;i<=m;i++) f[i][i]=add(a[i],a[i]); for(int i=m;i>=1;i--) for(int j=i+1;j<=m;j++){ k1=add(f[i+1][j],a[i]); k2=add(f[i][j-1],a[j]); f[i][j]=cmp(k1,k2); f[i][j]=add(f[i][j],f[i][j]); } res=add(res,f[1][m]); } ///////////////////////////////////////////////////////////// int main() { scanf("%d%d",&n,&m); res.a[0]=1; for(int i=1;i<=n;++i){ init(); solve(); } //output for (int i=res.a[0];i>0;i--) printf("%d",res.a[i]); cout<<endl; return 0; }
bign+dp 矩阵取数
时间: 2024-10-05 06:32:24