首先我们要知道,我们不会给同一个位置的数字重复清零操作,因为后一次清零会完全浪费前一次清零。所以我们最多只会进行n次清零。
其次,这道题给人有一种错觉,使用清零次数与达成目标之间存在单调性的关系,即用的清零次数越多,就越容易实现sum<=x的目标。
我们先承认这种错觉。那么它会引导我们用二分搜值的思想,即给定清零次数T,我们是否能构造一种方案使得sum<=x
呢? 我们想象一下,使用了T次清零之后,剩余的sum必然是这种形式
sum = {0 + nums2[a]*1 + nums2[b]*2 + ... + nums2[c] * (T-1)} +
{nums1[x]+nums2[x]*T + nums1[y]+nums2[y]*T + .... nums1[z]+nums2[z]*T}
也就是说,我们需要将元素分为两部分,前一部分是apply了清零操作,后一部分是没有apply清零操作。显然,对于前一部分,为了使得sum最小,我们会按照nums2的数值倒序排列。对于后一部分,对于顺序没有要求。
那么我们该如何将元素进行最优的分割呢?暴力尝试的话需要2^n。有更好的方法吗?其实这可以考虑成01背包问题,我们将所有元素按照nums2升序排序:每个元素有“取”或者“不取”两种决策,求取T个元素时的最小代价。所以我们很容易定义dp[i][j]表示前i个元素里面清零j个元素的最小代价。
- 当清零第i个元素时,因为nums2值最大,第i个元素必然是最后一个被清零才合算。说明我们在前i-1个元素依然用了j-1次清零,第j次清零使得nums[i]以0进入代价,同时也让之前的i-1个元素多了一轮“回血”,故增加的代价是nums2[1:i-1]。
- 当不清零第i个元素时,说明第i个元素此时经历了j轮回血,故增加的代价是
nums1[i]+nums2[i]*j
。
综上我们可以计算出任意的dp[i][j]. 通过dp[i][T]<=x
就可以判断能否通过T次清零实现目标。
但是注意,本题里的单调性是不成立的。例如
[9,10,10,5,2,4]
[2,4,0,3,3,4]
40
这组数据。不清零已经符合条件。清零1次,反而结果最小只能是42了。有可能确实没有单调性。
事实上,一次DP已经解决所有的问题。我们只需寻找最小的j,使得dp[i][j]<=x
即是答案。