首页 > 其他分享 >使数组和小于等于 x 的最少时间

使数组和小于等于 x 的最少时间

时间:2023-08-09 19:11:33浏览次数:28  
标签:小于 begin end int ids 最少 数组 nums1 nums2

给你两个长度相等下标从 0 开始的整数数组 nums1 和 nums2 。每一秒,对于所有下标 0 <= i < nums1.length ,nums1[i] 的值都增加 nums2[i] 。操作完成后 ,你可以进行如下操作:
选择任一满足 0 <= i < nums1.length 的下标 i ,并使 nums1[i] = 0 。
同时给你一个整数 x 。请你返回使 nums1 中所有元素之和 小于等于 x 所需要的 最少时间,如果无法实现,那么返回 -1 。

1. 动态规划

分析

  • 若存在实现的情况,则每个数最多移除一次,两次的情况必然更差
  • 要使得当前移除最优,要让增加越多的越晚移除,所以要根据数组2决定移除顺序
  • 根据升序结果,如果是已经决定选的,放到后面选才能使得最优(即如果已经决定选取数字,不用再考虑顺序)
  • 根据升序遍历,对于每个数,只需确定选与不选即可
  • 选取多少个数同样也是一个维度,最终确定为二维动态规划
  • 由于指定选取个数的增加量都一样,这里动态规划值确定为最大消除量,避免对前面选取的数再进行计算

dp[i][j]表示从前i个数中选出j个数的最大减少量

class Solution {
public:
    int minimumTime(vector<int>& nums1, vector<int>& nums2, int x) {
        int n = nums1.size();
        int sum = accumulate(nums1.begin(),nums1.end(),0);
        int add = accumulate(nums2.begin(),nums2.end(),0);

        vector<int> ids(n);//记录升序顺序
        iota(ids.begin(), ids.end(), 0);
        sort(ids.begin(), ids.end(), [&](const int i, const int j) {
            return nums2[i] < nums2[j];
        });
        //如果是已经决定选的,一定要放到后面选,才能使得最优化
        int dp[n+1][n+1];//dp[i][j]表示从前i个数中选出j个数的最大减少量
        memset(dp,0,sizeof(dp));
        for(int i=1;i<=n;i++){//升序遍历可选数,决定当前数选不选
            int cur = ids[i-1];//当前可选数下标
            for(int j=1;j<=i;j++)
                dp[i][j] = max(dp[i-1][j],dp[i-1][j-1]+nums1[cur]+nums2[cur]*j);
        }

        for(int i=0;i<=n;i++){
            int sub = dp[n][i];//选择不同个数时的最大削减量
            int remain = sum + add*i - sub;
            if(remain<=x) return i;
        }
        return -1;
    }
};

2. 一维优化

class Solution {
public:
    int minimumTime(vector<int> &nums1, vector<int> &nums2, int x) {
        int n = nums1.size();
        // 对下标数组排序,避免破坏 nums1 和 nums2 的对应关系
        vector<int> ids(n);
        iota(ids.begin(), ids.end(), 0);
        sort(ids.begin(), ids.end(), [&](const int i, const int j) {
            return nums2[i] < nums2[j];
        });

        vector<int> f(n + 1);
        for (int i: ids) //遍历可选数
            for (int j = n; j; j--) //右后往前遍历,避免覆盖
                f[j] = max(f[j], f[j - 1] + nums1[i] + nums2[i] * j);

        int s1 = accumulate(nums1.begin(), nums1.end(), 0);
        int s2 = accumulate(nums2.begin(), nums2.end(), 0);
        for (int t = 0; t <= n; t++)
            if (s1 + s2 * t - f[t] <= x)
                return t;
        return -1;
    }
};

标签:小于,begin,end,int,ids,最少,数组,nums1,nums2
From: https://www.cnblogs.com/929code/p/17617787.html

相关文章

  • php如何定义多维数组以某个字符去输出对应的值
    $arr=[['id'=>123,'test'=>['id'=>2,'title'=>"测试",'test3'=>['list'=>123]]]];$field="test.test3.list";foreach($ar......
  • 2018牛客多校第五场 F take[树状数组]
    理解题目画了一个二叉树,然后思维定势让我想构建一个有n层的二叉树,然后统计叶子节点。。有点恐怖。但是正解是考虑每一个箱子对答案的贡献。图片来自take_baymax520的博客对于每个箱子,它要发生交换也就是为答案贡献的条件是它当前宝石大小小于它的大小。对于比它小的宝石之前取......
  • 树状数组
    初步感受已知\(a_i\),求\(\sum_{i=1}^7a_i\)。暴力:\(ans=a_1+a_2+a_3+a_4+a_5+a_6+a_7\)时间复杂度:\(O(n)\)树状数组:已知\(A=\sum_{i=1}^4a_i\),\(B=\sum_{i=5}^6a_i\),\(C=\sum_{i=7}^7a_i\),则\(ans=A+B+C\)时间复杂度:\(O(\logn)\)这就是树状数组能快速求解信息的......
  • luogu P4200 千山鸟飞绝 题解 【一维数组套平衡树】
    目录题目解题思路code题目题目链接解题思路首先,此题有明显的插入、删除、查找,所以必须要使用平衡树。考虑如何使用平衡树维护每个鸟的状态。发现很不方便,因为鸟的位置改变,整个平衡树的值都要修改。考虑针对每个节点开一颗平衡树,这样就有\(3e4\times3e4\)棵树。这显然太多了......
  • TypeScript中使用数组的filter方法
    constarr:string[]=['pom','皮蛋编程','非常厉害','太棒了'];constfilteredArr:string[]=arr.filter((str:string)=>{returnstr.includes('编程');});console.log(filteredArr);//["皮蛋编程"] ar......
  • 2023-08-08:给你一棵 n 个节点的树(连通无向无环的图) 节点编号从 0 到 n - 1 且恰好有 n
    2023-08-08:给你一棵n个节点的树(连通无向无环的图)节点编号从0到n-1且恰好有n-1条边给你一个长度为n下标从0开始的整数数组vals分别表示每个节点的值同时给你一个二维整数数组edges其中edges[i]=[ai,bi]表示节点ai和bi之间有一条无向边一条好路......
  • 2023-08-08:给你一棵 n 个节点的树(连通无向无环的图) 节点编号从 0 到 n - 1 且恰好有 n
    2023-08-08:给你一棵n个节点的树(连通无向无环的图)节点编号从0到n-1且恰好有n-1条边给你一个长度为n下标从0开始的整数数组vals分别表示每个节点的值同时给你一个二维整数数组edges其中edges[i]=[ai,bi]表示节点ai和bi之间有一条无向边一条好路径需要......
  • 树状数组学习笔记
    树状数组作为一个常数小且好写的数据结构,虽然功能没有线段树那么齐全,但是其中的扩展内容还是很多的。维护区间和1.0BIT的作用树状数组可以做到单次logn求前缀和,单次logn修改信息维护一个前缀和。1.1区间修改单点查询考虑维护差分数组\(c[i]=a[i]-a[i-1]\)。在查询......
  • 前端基础-数组方法
    数组方法备忘单:添加/删除元素:push(...items) ——向尾端添加元素,pop() ——从尾端提取一个元素,shift() ——从首端提取一个元素,unshift(...items) ——向首端添加元素,splice(pos,deleteCount,...items) ——从 pos 开始删除 deleteCount 个元素,并插入 i......
  • 树状数组
    大佬的讲解视频讲解两者搭配食用效果更佳树状数组就是一个树状数组的板子题intlowbit(intx){returnx&(-x);}求最低位1代表的值是多少voidadd(intx,inty){while(x<=n){c[x]+=y;x+=lowbit(x);}}将包含这个数的每一个值都更新int......