题意:
给出一个n*m的矩阵,每一次取数从每一行中取一个数,每行取数的得分为每行所取数a[i][j] * 图片说明 ,k表示第几次取,且每次取数只能取头或者尾。求取完后的得分最大值?

思路:
我们可以发现每一行的取数只与当前行有关,所以该题相当于求n次数组中取数得分之和。
我们可以区间dp解决。每一次不断增加区间长度,区间长度为1时相当于该数为最后一个取得。
状态转化方程:
dp[i][j]=max(dp[i+1][j]+(a[i]<<(j-i+1),dp[i][j-1]+(a[j]<<(j-i+1)));
结果将每一行的dp[1][m]加起来就好。

注意:对于数据范围最好用__int128,否则只能用高精度了。

代码:

#include <bits/stdc++.h>
#define inf 99824435300000
using namespace std;

typedef long long ll;

inline __int128 read()
{
    __int128 x=0,f=1;
    char c=getchar();
    while(c<'0'||c>'9')
    {
        if(c=='-')
        {
            f=-f;
        }
        c=getchar();
    }
    while(c>='0'&&c<='9')
    {
        x=(x<<1)+(x<<3)+(c^48);
        c=getchar();
    }
    return f*x;
}

inline void write(__int128 x)
{
    if(x<0)
    {
        putchar('-');
        x=-x;
    }
    if(x>9)
        write(x/10);
    putchar(x%10+'0');
}

struct w
{
    ll x, y;
} w, w2;

__int128 a[105], dp[105][105], sum=0;

int main()
{
    int n, m;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
    {
        memset(dp,0,sizeof(dp));
        for(int j=1;j<=m;j++)
        {
            a[j]=read();
            dp[j][j]=a[j]<<m;
        }
        for(int k=2;k<=m;k++)
        {
            for(int j=1;j+k-1<=m;j++)
            {
                    dp[j][j+k-1]=max(dp[j][j+k-2]+(a[j+k-1]<<(m-k+1)),dp[j+1][j+k-1]+(a[j]<<(m-k+1)));
            }
        }
        sum+=dp[1][m];
    }
    write(sum);
    return 0;
}