P1005 矩阵取数游戏

题面

click

前言

这题写高精多麻烦啊,一个 __int128 就可以完全把高精替换掉,代码还比高精的短。

然后,我就用 __int128 水过去了。(绝对不是我懒得写高精呢)。

题解

一句话题意 每次取数从每一行行首或行末取一个,每次取都有一定的价值,问你怎么取价值最大。

首先,每一行可以分开来考虑,我们最后的答案就是每一行最优结果相加。

那问题就转化为了,我们怎么在一行取使这一行价值最大。

大家都很容易想到区间 dp吧。

状态是 \(f[i][j]\) 表示这一行剩下从 \(i\)\(j\),其他都被选上的最大价值

转移方程 \(f[i][j] = max(f[i-1][j]+a[k][j] \times 2^{m+i-j-1} , f[i][j+1] + a[k][j] \times 2^{m+i-j-1})\)

转移时要注意第一层是正序枚举的,但第二层却要倒序枚举。

Code

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
inline __int128 read()
{
    __int128 s = 0,w = 1; char ch = getchar();
    while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
    while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
    return s * w;
}
__int128 n,m,tot,ans,w[110][110],f[110][110],base[110];
void print(__int128 x)//手写输入函数
{
	if(x>9)
	{
		print(x/10);
	}
	cout<<(int) (x%10);
}
int main()
{
    n = read(); m = read(); base[0] = 1;
    for(int i = 1; i <= m; i++) base[i] = base[i-1] * 2;//预处理出二的幂次方
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= m; j++)
        {
            w[i][j] = read();
        }
    }
    for(int i = 1; i <= n; i++)
    {
        memset(f,0,sizeof(f)); tot = 0;//每做一行都要清空
        for(int l = 1; l <= m; l++)
        {
            for(int r = m; r >= 1; r--)//转移
            {
                f[l][r] = max(f[l][r],f[l-1][r]+w[i][l-1]*base[m+l-r-1]);
                f[l][r] = max(f[l][r],f[l][r+1]+w[i][r+1]*base[m+l-r-1]);
            }
        }
        for(int j = 1; j <= m; j++) tot = max(tot,f[j][j]+w[i][j]*base[m]);
        ans += tot;
    }
    print(ans);
    return (int)0;
}

posted @ 2020-08-29 14:17  genshy  阅读(148)  评论(0编辑  收藏  举报