【题解】P1005 矩阵取数游戏
题面
前言
再也不手搓高精了,调了三个点还是没出来,最后老老实实写 __int128
正文
显然行与行之间都是相互独立的子问题
区间 DP 捏!
我们记 \(f_{i,j}\) 表示取数取到只剩区间 \([i,j]\) 的最优得分
初始化都是 \(0\)
考虑转移
区间 \([i,j]\) 只能由 \([i-1,j]\) 或 \([i,j+1]\) 转移
那么依照题意,将对应的 \(a_i\) 加上即可
形式化地说,转移方程形如
f[i][j]=max(f[i][j],f[i-1][j]+p[m-j+i-1]*a[i-1]);
f[i][j]=max(f[i][j],f[i][j+1]+p[m-j+i-1]*a[j+1]);
接下来是计算答案环节
因为我们取走一行所有数,我们需要去比较所有的 \(f_{i,i}\),寻找最大值
所以有 \(ans = \sum_{k=1}^{n} {\mathop{\max}\limits_{i=1}^{m} \lbrace f_{i,i} \times 2^m \rbrace}\)
一些小细节
数据较大,需要使用 __int128,也就意味着要手搓输入输出
处理新的一行的 \(f\) 时,不要忘记初始化
STL 中自带的 pow 函数精度较低,建议手写 \(2\) 的幂
代码
#include<iostream>
#include<cstring>
#define int __int128
using namespace std;
const int maxn=85;
int n,m,a[maxn];
int p[maxn],f[maxn][maxn];
inline void input(int &s){
s=0;
char c=' ';
while(c>'9'||c<'0'){
c=getchar();
}
while(c>='0'&&c<='9'){
s=s*10+c-'0';
c=getchar();
}
return;
}
inline void output(int x){
if(x>9){
output(x/10);
}
putchar(x%10+'0');
return;
}
inline void init(){
p[0]=1;
for(int i=1;i<=84;i++){
p[i]=p[i-1]*2;
}
return;
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
input(n);
input(m);
init();
int ans=0;
for(int k=1;k<=n;k++){
memset(f,0,sizeof(f));
for(int i=1;i<=m;i++){
input(a[i]);
}
memset(f,0,sizeof(f));
for(int i=1;i<=m;i++){
for(int j=m;j>=i;j--){
f[i][j]=max(f[i][j],f[i-1][j]+p[m-j+i-1]*a[i-1]);
f[i][j]=max(f[i][j],f[i][j+1]+p[m-j+i-1]*a[j+1]);
}
}
int res=0;
for(int i=1;i<=m;i++){
res=max(res,f[i][i]+p[m]*a[i]);
}
ans+=res;
}
output(ans);
return 0;
}
后记
云落的沉默震耳欲聋
完结撒花!

浙公网安备 33010602011771号