[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
posted @ 2024-02-15 10:21  HaneDaniko  阅读(15)  评论(0编辑  收藏  举报