区间DP矩阵取数游戏
Posted 行码棋
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了区间DP矩阵取数游戏相关的知识,希望对你有一定的参考价值。
- 博客主页: https://blog.csdn.net/qq_50285142
- 欢迎点赞👍收藏✨关注❤留言 📝 如有错误,敬请指正
- 🎈虽然生活很难,但我们也要一直走下去🎈
原题链接
题意:
对于一个给定的n×m
的矩阵,矩阵中的每个元素 均为非负整数
游戏规则如下:
每次取数时须从每行各取走一个元素,共n
个。经过m
次后取完矩阵内所有元素;
每次取走的各个元素只能是该元素所在行的行首或行尾;
每次取数都有一个得分值,为每行取数的得分之和,每行取数的得分 = 被取走的元素值 × 2 i 2^i 2i, 其中i
表示第i
次取数(从1
开始编号),游戏结束总得分为m
次取数得分之和。
对于任意矩阵,可以求出取数后的最大得分。
思路:
可以发现每行之间的结果互不影响,所以我们只需要弄明白怎么求一行的最大值即可
求一行区间的最大值,自然想到区间DP
区间DP是从小区间更新到大区间,我们可以考虑状态表示
状态表示:
f [ i ] [ j ] f[i][j] f[i][j]表示区间 [ i , j ] [ i , j ] [i,j]中取数得到的最大值,这是取数的次数自然是 j − i + 1 j-i+1 j−i+1次
状态转移:
一个区间一般都是由两个状态转移过来,一个是前面少一个元素,一个是后面少一个元素。即
f [ i ] [ j ] = m a x ( f [ i + 1 ] [ j ] + a [ k ] [ i ] ∗ 2 m − j + i , f [ i ] [ j − 1 ] + a [ k ] [ j ] ∗ 2 m − j + i ) f[i][j] = max(f[i+1][j]+a[k][i]*2^{m-j+i},f[i][j-1]+a[k][j]*2^{m-j+i}) f[i][j]=max(f[i+1][j]+a[k][i]∗2m−j+i,f[i][j−1]+a[k][j]∗2m−j+i)
其中少的那一个元素为第 m − j + i m-j+i m−j+i次取数,所以为相应的值乘2的对应幂次,一直从小的区间转移,直到转移到大区间
但是区间DP我喜欢用len
长度的写法,所以相对应的转移方程就要变一下,其实本质不变
f [ l ] [ l + l e n − 1 ] = m a x ( f [ l + 1 ] [ l + l e n − 1 ] + a [ k ] [ l ] ∗ f a c t [ m − l e n + 1 ] , f [ l ] [ l + l e n − 2 ] + a [ k ] [ l + l e n − 1 ] ∗ f a c t [ m − l e n + 1 ] ) f[l][l+len-1] = max(f[l+1][l+len-1]+a[k][l]*fact[m-len+1], f[l][l+len-2]+a[k][l+len-1]*fact[m-len+1]) f[l][l+len−1]=max(f[l+1][l+len−1]+a[k][l]∗fact[m−len+1],f[l][l+len−2]+a[k][l+len−1]∗fact[m−len+1])
本题需要注意的是:
题目中数组中存储的数据超出了64位,但是发现int128
可以满足数据范围的要求,所以就使用int128
比较简便,int128
和int
差不多,就是读入输出需要写一个对应的函数,其他的使用都一样
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e5+100;
__int128 f[1005][1005],fact[100],res;
int n,m,a[1005][1005];
inline __int128 read()
{
__int128 x = 0;
int f = 1;
char ch;
ch = getchar();
while(ch<'0' || ch>'9')
{
if(ch=='-')
{
f = -1;
ch = getchar();
}
}
while(ch>='0' and ch<='9') x = x*10+ch-'0',ch=getchar();
return x*f;
}
void print(__int128 x)
{
if(x<0)
{
putchar('-');
x = -x;
}
if(x>9) print(x/10);
putchar(x % 10+'0');
}
void solve()
{
fact[0] = 1;
for(int i=1;i<=80;i++)
fact[i] = fact[i-1] * 2;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
for(int j=1;j<=m;j++)
scanf("%d",&a[i][j]);
for(int k=1;k<=n;k++)
{
for(int i=1;i<=m;i++) f[i][i] = a[k][i] * fact[m];
for(int len=2;len<=m;len++)
{
for(int l=1;l+len-1<=m;l++)
{
f[l][l+len-1] = max(f[l+1][l+len-1]+a[k][l]*fact[m-len+1],
f[l][l+len-2]+a[k][l+len-1]*fact[m-len+1]);
}
}
res += f[1][m];
}
print(res);
}
int main()
{
int _;
// cin>>_;
_ = 1;
while(_--)
{
solve();
}
return 0;
}
往期优质文章推荐
以上是关于区间DP矩阵取数游戏的主要内容,如果未能解决你的问题,请参考以下文章