[TK] 矩阵取数游戏<简单版> hzoi-tg-906-2
本题是一个坐标DP问题
状态转移
首先我们注意到,一个状态只能由两种前置状态得到:取左边的数和取右边的数,因此我们以状态为阶段定义如下:
\(f[a][b][c]\) 为状态转移数组,其中 \(a\) 为已取走的数目,区间 \([b,c]\) 为未取走的所有数组成的区间(能够发现,未取走的所有数组成的区间一定是连贯的,所以我们这样定义),数组表示该状态下的最大得分.
根据上述推论,可以得出状态转移方程:
\[f[k][i][j]=max
\begin{cases}
f[k-1][i][j+1]+cost[j+1]\\
f[k-1][i-1][j]+cost[i-1]
\end{cases}
\]
其中上面的转移式是取右边的数,下面的转移式是取左边的数. \(cost[i]\) 表示拿走这个数的得分.
细节处理
1.结果输出
我们可以发现,在拿走 \(n-1\) 个物品后,区间内一定会剩余一个,也就是此时状态转移方程为 \(f[n-1][i][i]\) 的形式.
我们可以直接找出所有 \(f[n-1][i][i]+cost[i]\) 中的最大值作为答案.
2.计算 \(cost[i]\)
不难发现,本题中 \(cost[i]=s[i] \times 2^{k}\). 有人会想到快速幂,但是题目最大只有 \(k=30\),所以还是打表更有性价比.我们直接在开头预处理全部数值存进数组就行.
代码实现
假如你是来抄代码的 建议你动点脑子理解一下上面的东西 这里只给出伪代码
for(int i=1;i<=n;++i){ //预处理
base[i]=base[i-1]*2;
}
for(int i=1;i<=n;++i){
cin>>y[i];
}
for(k:1~n-1){
for(i:1~n){
for(j:1~n){
f[k][i][j]=max(f[k-1][i][j+1]+y[j+1]*base[k],f[k-1][i-1][j]+y[i-1]*base[k]);
}
}
}
for(i:1~n){
ans=max(f[n-1][i][i]+y[i]*base[n],ans);
}
}
//别忘了开long long