感觉这种形式得动态规划也有很多类型,反正就是从两边取数,按照一定得规则把这个数做一个计算。
题解:
看这个题,他问的是一个矩阵如何取数,我们可以发现,对于每一行如何取数,题目中只是说从两边取,并没有说明行与行之间的要求,那么这个问题就可以化简一下了,我们对每行进行动态规划,分别求出每行如何取数的最大值然后加起来即可。
那么对于每一行应该如何取数呢。
递推的话,题目是从两边开始往内取,如果我们按照题目的要求从两边递推,似乎有点难办
所以我们就倒着来,先确定了区间长度,然后这个区间可以由两边推得,那么相应的 计算方法也会变成2的(m-length+1)次方了,因为一需要先把两边的数取干净才可以。
2的80次方 会爆longlong,所以可以用 _ _int128(横线中间无空格) 这个东西貌似再windows上面无法编译,所以调试的时候用longlong即可,最后把longlong改成__int128
代码:

/*Keep on going Never give up*/
#pragma GCC optimize(3,"Ofast","inline")
#include <bits/stdc++.h>
const int maxn = 100;
const int MaxN = 0x3f3f3f3f;
const int MinN = 0xc0c0c00c;
typedef __int128 ll;
const int mod = 100000000;
using namespace std;
int a[maxn][maxn];
int n,m;
ll dp[maxn][maxn];

ll quick(ll a,ll b){
    ll res=1;
    while(b){
        if(b&1) res*=a;
        a*=a,b/=2;
    }
    return res;
}

ll get_ans(int x){
    for(int i=0;i<maxn;i++){
        for(int j=0;j<maxn;j++){
            dp[i][j]=0;
        }
    }
    for(int i=1;i<=m;i++){
        for(int l=1,r=i;r<=m;l++,r++){
            dp[l][r]=max(dp[l+1][r]+(ll)a[x][l]*quick(2,m-i+1),dp[l][r-1]+(ll)a[x][r]*quick(2,m-i+1));
            //cout<<dp[l][r]<<endl;
        }
    }
    return dp[1][m];

}
void print(ll x)
{
    if(x==0) return;
    print(x/10);
    char num=x%10+'0';
    putchar(num);
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>a[i][j];
        }
    }
    ll ans=0;
    for(int i=1;i<=n;i++){
        ans+=get_ans(i);
    }
    if(ans==0) printf("0");
    else print(ans);
    return 0;
}