『题解』CodeForces CF1676E Eating Queries

题目传送门

题目大意

\(n\) 颗糖,吃掉第 \(i\) 颗糖可以获得 \(a_i\) 点糖分。

\(q\) 次询问,每次询问最少吃多少颗糖可以得到不小于 \(x\) 的糖分,无解输出 \(-1\)

思路

既然问最少吃多少颗糖,那糖分大的自然优先级要大。

于是就可以把 \(a\) 数组降序排列。

询问时还需要知道 \(a\) 数组前 \(k\) 个糖的糖分之和,我们可以在询问之前对 \(a\) 数组进行一次前缀和,也就是将原来的 \(a_i\) 变成 \(\sum\limits^{i}_{j=1}a_j\)。这样转化很简单,只需要 \(\mathcal{O}(n)\) 循环一遍,每次使得 \(a_i\) 加上 \(a_{i-1}\),注意 \(a_{i-1}\) 是之前处理过的。

可以发现经过处理后的 \(a\) 数组满足单调性,所以在查询时可以直接二分找到第一个 \(\ge x\) 的数,取这个数的下标即可。这里可以直接用 lower_bound

当得到的下标高于 \(n\) 时,说明无解,输出 \(-1\)

代码

#include <iostream>
#include <algorithm>
using namespace std;
const int N=15e4+5;
int t,n,q,x,ans;
int a[N];

int main(){
    cin >> t;
    while(t--){
        cin >> n >> q;
        for(int i=1; i<=n; i++) cin >> a[i];
        // 逆序排序
        sort(a+1,a+n+1,[](int x,int y)->bool{return x>y;});
        for(int i=1; i<=n; i++) a[i]+=a[i-1]; // 前缀和
        while(q--){
            cin >> x;
            ans=lower_bound(a+1,a+n+1,x)-a;
            if(ans<=n) cout << ans << endl;
            else puts("-1");
        }
    }
    return 0;
}
posted @ 2022-05-23 18:03  仙山有茗  阅读(178)  评论(0)    收藏  举报