『题解』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;
}

浙公网安备 33010602011771号