CF1676E - Eating Queries

该文章介绍了如何解决CF1676E问题,主要策略是通过对糖分数组进行降序排序,计算前缀和,然后使用二分查找找到满足特定糖分目标所需的最小糖果数量。在O(T*n*logn)的时间复杂度和O(N)的空间复杂度下完成任务。
摘要由CSDN通过智能技术生成

CF1676E - Eating Queries

题目

Eating Queries - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

思路

  • 由题意很容易得知,我们每次都吃最大的糖分的糖,得到的答案一定最小。
  • 可以先对数组进行排序,从大到小吃糖,但数据量很大不能一个个吃。
  • 可以对排序后的数组求前缀和数组。
  • 设前缀和数组pre[N],pre[i]表示吃i(0 ~ n)颗糖可以得到的最大糖分。
  • 设target为所需糖分,我们可以对pre数组进行二分找到最小的糖数,结束条件l > r
  • 当pre[mid] < target时,说明吃mid颗糖还不够,所以l = mid + 1;
  • 当pre[mid] >= target时,说明吃mid颗足够了但颗数不一定是最小的,
  • 所以还要继续二分,当二分结束时得到的颗数才是最小的,r = mid - 1。

代码

#include <bits/stdc++.h>
using namespace std;

const int N = 2e5 + 7;

int T;

int main() {
    cin >> T;
    // T组测试样例
    while (T--) {
        // 原始数组
        int arr[N] = {0}; 
        // 前缀和数组
        int pre[N] = {0};
        // n颗糖,k个询问
        int n, k;
        scanf("%d%d", &n, &k);
        // 读入数据
        for (int i = 0; i < n; i++) {
            scanf("%d", &arr[i]);
        }
        // 从大到小排序,定义自定义排序,lambda表达式实现
        sort(arr, arr + n, [](int a, int b){return a > b;});
        // 下标从1开始,应为0颗为0糖分
        for (int i = 1; i <= n; i++) {
            // 计算前缀和
            pre[i] = arr[i - 1] + pre[i - 1];
        }
        // k组询问
        while (k--) {
            // 二分区间[1, n]颗糖
            int l = 1, r = n;
            // 目标糖分
            int target;
            scanf("%d", &target);
            // 初始化ans为-1,若不存在即为-1
            int ans = -1;
            // 当l > r时跳出循环,当l == r可能存在答案
            while (l <= r) {
                // 计算中间值,利用减法防止爆数据范围
                int mid = l + (r - l) / 2;
                // pre[mid] < target 颗数还不够
                if (pre[mid] < target) {
                    // 左边的太小舍去
                    l = mid + 1;
                } else {
                    // pre[mid] >= target 颗数够了
                    // 更新ans
                    ans = mid;
                    // 右边已经考虑过了
                    r = mid - 1;
                }
            }
            // 输出答案
            printf("%d\n", ans);
        }
    }
    return 0;
}

复杂度分析

  • 时间复杂度O(T * n * logn)
  • 空间复杂度O(N)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值