矩阵取数游戏
一道很简单的区间dp,竟然是道蓝 赶快去水积分吧
读题后不难发现,不同行的取数决策并不影响其它行的答案,因此我们dp时只要搞出每行的最大值,加起来就是答案了
对于每一行,我们只可以取行头或者行末,取完后剩下的数必定还是一段连续区间,且很容易通过大区间的答案推出小区间答案,是区间dp没错了
不妨设\(dp[i][j]\)为取完后剩下的数区间为\([i,j]\)时,答案的最大值。易得转移方程\(dp[i][j]=max(dp[i+1][j]+2^{m-(j-i)}*v[i],dp[i][j+1]+2^{m-(j-i)*v[j]} )\)
但是这个dp只可以取到只剩一个数,还要再把每个\(dp[i][i]\)再算一遍,\(ans=max\){\(dp[i][i]+2^m*v[i]\)}
关于高精问题,建议用int128
贴码,有些细节码里讲
#include <bits/stdc++.h>
using namespace std;
const int N=100;
int n,m;
__int128 a[N][N],f[N][N];
template<class T>
inline void read(T &x){
x=0;int w=1;
char ch=getchar();
while(ch<'0'||ch>'9') {if(ch=='-') w=-1;ch=getchar();}
for(;ch>='0'&&ch<='9';ch=getchar())
x=(x<<3)+(x<<1)+(ch&15);
x*=w;
}
inline void write(__int128 x){
if(x<0){
putchar('-');
x=-x;
}
if(x>9)
write(x/10);
putchar(x%10+'0');
}
__int128 dp(__int128 sum[])
{
memset(f,0,sizeof(f));
int i,j;
for(i=0;i<m;i++)//由于dp[i][j]是由大区间推出来的,所以先循环大区间
for(j=1;i+j<=m;j++)
f[j][i+j]=max(2*(f[j+1][i+j]+sum[j]),2*(f[j][i+j-1]+sum[i+j]));
return f[1][m];
}
int main()
{
read(n),read(m);
int i,j;
for(i=1;i<=n;i++)
for(j=1;j<=m;j++)
read(a[i][j]);
__int128 ans=0;
for(i=1;i<=n;i++)
ans+=dp(a[i]);//分行分别计算
write(ans);
return 0;
}
本文来自博客园,作者:羊扬羊,转载请注明原文链接:https://www.cnblogs.com/sheepcsy/p/16416607.html