问题描述
小E在一个游戏中遇到了 个按顺序出现的怪物,每个怪物都有其特定的血量 和攻击力 。小E的初始血量为 ,攻击力为 。 游戏规则如下:
- 小E可以击败一个血量和攻击力都小于她当前属性的怪物。
- 对于第一个击败的怪物,需要满足其血量小于 且攻击力小于 。
- 击败怪物后,小E会获得该怪物的属性值。
- 为了保持战斗节奏,要求击败的怪物序列中,后一个怪物的血量和攻击力都必须严格大于前一个怪物。
小E想知道,她最多能击败多少怪物。
思路历程
首先要注意,这道题目疑似是有极大问题的,一个是数据可能极弱,一个是题意非常之不明确。
初步设想
通过对多篇题解的分析,我认为这篇题解是接近真正解的6.小E的怪物挑战 ):
动态规划数组就是:
我们用 dp[i] 表示以第 个可击败怪物结尾的最长递增子序列的长度。
初始化每个 dp[i] 的值都为 1,因为每个怪物至少可以单独成为一个子序列。
状态转移就是:
- 对于每一个怪物 ,遍历所有之前的怪物 (
j < i),如果怪物 的血量和攻击力都小于怪物 的血量和攻击力(即h[j] < h[i]且a[j] < a[i]),那么我们可以将怪物 添加到以怪物 结尾的子序列中。 - 更新
dp[i]的值为dp[j] + 1,表示在以 结尾的子序列基础上增加怪物 。 - 取所有可能的
dp[j] + 1中的最大值,赋给dp[i]。 - 那么最终答案就是每一个子序列长度的最大值
但是这篇题解依托于一个条件:从左打怪打到右,即数据已经有序,这是非常致命的一个条件,因为我们很容易构造一个 hack:把原本能打到的一个怪放在第一个,根据这些默认从左往右打怪的伪正解,第一个怪是无法被加入最长公共子序列的。
尽管以上思路是伪正解,但是出于题目数据弱,可以通过。
深入讨论
发现问题了吗?
对啊, LIS 要保证序列自身是单调的啊,不然你单调个毛线最长递增子序列?
如何排序?我们知道在单一变量贪心问题上,直接单关键字排序即可,又或者在《国王游戏》这道极其经典的双变量贪心问题上,通过讨论得到一个新的单一关键字进行排序。但是由于此题的特殊条件,我们恐怕很难找到一个单一关键字可以实现这样的排序。其实,直接双关键字排序,正确性是有保障的:
对于另一个众多题解忽略的问题:攻击力 H 和血量 A 的变化问题,用 h,a 数组分别表示以 i 结尾时,小E的数值大小,转移时加上一层比较即可。
如此,我们便讨论出了真正的正解