📅  最后修改于: 2023-12-03 14:58:37.834000             🧑  作者: Mango
在一条直线上有 $n$ 个门,从左到右依次编号为 $1\sim n$。其中某些门上挂了锁,有些门能通过,有些门不能通过,每个门有一个开锁的权值 $w_i$。
你的任务是把能够通过的门全部打开。开始,所有门都是关着的。每次可以花费 $a$ 点能量打开一个门,也可以花费 $b$ 点能量换咒释放掉相邻两个门上的所有锁。经过释放咒的相邻两个门可以直接通过,释放咒后 doOrDie 咒会使得路径上最小长度锁值出现 $m$ 次,从而打开不能通过的门。
请计算在最小花费下,能够把门全部打开的方法。
第一行,五个整型变量,分别为 $n$、$m$、$a$、$b$、$s$。
接下来一行 $n$ 个整数,分别为 $w_1$ 到 $w_n$。
输出打开所有门的最小花费。
对于 $50%$ 的数据,$n\leq 200$ 。
对于 $100 %$ 的数据,$1\leq n\leq 3000,1\leq m,w_i\leq 100,1\leq a,b,s\leq 100$
10 2 2 1 2
1 2 1 2 2 2 2 2 2 2
16
这是一道动态规划问题。首先定义一个状态,$f(i,j)$ 表示前 $i$ 个门已经全部开着,其中最小值为 $j$ 的最小花费,这里最小值是指不通过任何一个 $j$ 值出其他的开启门,这里的 $j$ 只是作为一个标识符,代表最小值。
对于 $f(i,j)$,它要么由 $f(i-1,k)$ 转移过来,要么对于不能开启的门(即 $w_i < j$ 的门)需要使用咒语。所以,我们有以下状态转移方程:
$$ f(i,j)=min(f(i-1,k)+a\times Min(i,k+1,j)+b,\quad 1\leq k\leq n, w_i\geq j) $$
其中,$Min(i,j,k)$ 表示 $[i,j]$ 中的最小值出现了恰好 $k$ 次,同时满足 $0\leq k\leq w_i$ 和 $0\leq k\leq j-i$(即不能把 $[i, j]$ 空间填满)。这里的 $Min(i, k+1, j)$ 就是用以释放相邻两个门的咒语,其返回值就是能够打开被锁住的门所需要的最小权值。
因为本题与前一个状态有关,我们需要维护前一个状态的信息,所以状态还可以简化为$g(j)$。这里的 $g(j)$ 表示前一个状态 $f(i-1, j)$ 的最小花费。
注意,$Min(i,j,k)$ 这个函数要用到前缀和实现,否则复杂度无法承受。具体参见样例代码。
C++ 代码