绝对 => 相对

52 阅读2分钟

110场双周赛 T4

Problem: 2809. 使数组和小于等于 x 的最少时间

如何比较两种方案的优劣?

=> 计算相对值往往比绝对值容易

  1. 答案最大是多少?

假设对一个下标操作了两次,其合并为一次更优

因此答案最大为n

  1. 从小到大枚举答案

t = 1, 选择当前最大的元素,归零

t = 2,如何比较不同的选取方式的优劣?

假设选取的下标为ij

=> 先ij or 先ji

如果有三个下标?

ijk
12 * nums2[i]1 * nums2[j]0
21 * nums2[i]2 * nums2[j]0
301 * nums2[j]2 * nums2[k]
402 * nums2[j]1 * nums2[k]
51 * nums2[i]02 * nums2[k]
62 * nums2[i]01 * nums2[k]

可以看出,其实本质上是对ijk分配从0开始的系数,从而得出不同的结果。

排序不等式:倒序乘积和 <= 乱序乘积和 <= 正序乘积和

=> 大的系数分配给大的nums2[k]

=> 将nums1按照nums2的大小重新排序,nums2越小,越先进行操作

原问题

=> 从nums1中选取一个子序列,子序列的元素分别变为 nums1[i] + j \times nums2[i] (j为元素在子序列中的索引), 最大化子序列的元素和

=> 最大子序列和变题

=> f[i+1][j]:前i个数中,选取长度为j的子序列,求最大的元素和

=> f[i+1][j] = Max(f[i][j], f[i][j-1] + nums1[i] + \times nums2[i])

代码

class Solution {
    public int minimumTime(List<Integer> nums1, List<Integer> nums2, int x) {
        int n = nums1.size();
​
        int sum1 = 0, sum2 = 0;
        var ids = new Integer[n];
        for (int i = 0; i < n; i++) {
            ids[i] = i;
            sum1 += nums1.get(i);
            sum2 += nums2.get(i);
        }
        // 按照nums2的大小, 从小到大排序
        Arrays.sort(ids, (i, j) -> nums2.get(i) - nums2.get(j));
​
        // 最大子序和的变体, 
        // dp[i+1][j]:前i个数中,选取长度为j的子序列,求最大的元素和
        int[][] dp = new int[n+1][n+1];
        
        for (int i = 0; i < n; i++) {
            for (int j = 1; j <= n; j++) {
                dp[i+1][j] = Math.max(dp[i][j], dp[i][j-1] + nums1.get(ids[i])+ j * nums2.get(ids[i]));
            }
        }
​
        for (int i = 0; i <= n; i++) { 
            if (sum1 + sum2 * i - dp[n][i] <= x) return i;
        }
    
        return -1;
    }