P1005 矩阵取数游戏
传送门
思路:
△ 区间动规
对于每行,有 f [ i ][ j ] 代表取区间 [ i , j ] 的最大值。
然后转移方程我们考虑,对于每一个新的 f [ i ][ j ],有两种情况(下面定义 a [ i ]代表该行的每个数):
①先取前面的(a [ i ]),再取剩下的 f [ i+1 ][ j ]即[ i+1 , j ]的最大值:2f [i+1][ j ] + 2a [ i ]即把接下来取的所有数乘上2,也就是把接下来取的所有数从x×2i变为x×2i+1即每次取都把之前的翻一倍,然后当前取的值 a [ i ]要乘上21即2
②先取后面的(a [ j ]),再取剩下的 f [ i ][ j−1 ]即[ i , j−1 ]的最大值:2f [ i ][ j-1 ] + 2a [ j ]同理
故转移方程为 f [ i ][ j ] = max( 2f [ i+1 ][ j ]+2a [ i ],2f [ i ][ j-1 ] + 2a [ j ] )
AC代码:
#include<bits/stdc++.h> #define max(x,y) (x>y?x:y) using namespace std; __int128 f[105][105],ans;//_int128 (高精,比int多一位)(int:127) int n,m,len,Ans[105],mp[105][105],a[105]; inline int read() { int kr=1,xs=0; char ls; ls=getchar(); while(!isdigit(ls)) { if(ls=='-') kr=-1; ls=getchar(); } while(isdigit(ls)) { xs=(xs<<1)+(xs<<3)+(ls^48); ls=getchar(); } return xs*kr; } int main() { n=read();m=read(); for(int i=1;i<=n;++i) for(int j=1;j<=m;++j) mp[i][j]=read(); for(int j=1;j<=n;++j) { memset(f,0,sizeof(f)); for(int i=1;i<=m;++i)a[i]=mp[j][i]; for(int len=0;len<=m;++len) { for(int i=1;i<=m-len;++i) { f[i][i+len]=max((a[i]<<1)+(f[i+1][i+len]<<1),(f[i][i+len-1]<<1)+(a[i+len]<<1)); } } ans+=f[1][m]; } while(ans) { Ans[++len]=ans%10; ans/=10; } if(len==0)return printf("0"),0; for(int i=len;i>=1;--i) printf("%d",Ans[i]); return 0; }