目录
题目
输入格式
输出格式
样例
提示
思路
代码
题目
单点时限: 2.0 sec
内存限制: 1024 MB
oxx 和 Xiejiadong 在玩一个双人旋转赛车的小游戏。
他们将进行一些比赛。每局比赛必须按顺序进行,胜者会得到该局对应的分数 xi。
由于 oxx 技艺不精(每局都可以由 Xiejiadong 决定胜负),因此他给自己设置了初始分数 k,希望自己能够一直领先 Xiejiadong。
不过 Xiejiadong 识破了 oxx 的诡计,现在 Xiejiadong 想知道自己至少需要赢几局才可以使得自己能够在某一时刻的比分不落后于 oxx。
若无法达到则输出 −1。
输入格式
第一行两个整数 n,k (1≤n≤106,1≤k≤109),表示游戏局数以及 oxx 初始分数。
第二行 n 个整数 xi (1≤xi≤109),表示每局游戏的分数。
输出格式
一个整数,表示答案。
样例
input
3 3 4 1 2
output
1
input
3 7 1 2 3
output
-1
提示
样例一:Xiejiadong 只需要赢第一局,即可获得 4 分,这时候就不落后于 oxx 3 分。
样例二:Xiejiadong 全胜也领先不了。
思路
难度评级:⭐️⭐️⭐️
贪心思想,是用二分法,将问题转化为判定性问题
重点是判定的函数怎么写:
1. 判定xie赢x局后是否有可能不输给oxx;
2. 先假设xie前x局都赢了,此时分数如果不低于oxx的,那么x局满足条件;
3. 否则,让xie先再赢一局,然后再输掉这些局中分数奖励最低的一局,如此往复,判断x局是否满足条件;
4. 每次都只需要获取分数最低的一局,所以只需要使用小根堆来记录xie赢得所有局即可,小根堆可以用priority_queue优先队列轻松实现;
代码
#include <iostream>
#include <vector>
#include <queue>
using namespace std;
typedef long long ll;
vector<int> point;
bool judge(int n,int k,int target) {
// 先统计前target局Xiejiadong都赢的情况
ll oxxPoint=k;
ll xiePoint=0;
priority_queue<int,vector<int>,greater<int>> q;// 默认是大根堆,less也是大根堆,小根堆是greater
for(int i=0;i<target;i++) {
q.push(point[i]);
xiePoint+=point[i];
if(xiePoint>=k) return true;
}
// 前target局都赢都没有办法超过oxx,下面开始紧跟着后面赢一局
// 然后输掉所有赢得局中分数最低的一局,如此循环
// 用优先队列实现小根堆,可以更快速地知道一些数据中的最小值
for(int i=target;i<n;i++) {
q.push(point[i]);
xiePoint+=point[i];
xiePoint-=q.top();
oxxPoint+=q.top();
q.pop();
if(xiePoint>=oxxPoint) return true;
}
return false;
}
int main(int argc, char** argv) {
int n,k;
cin>>n>>k;
point.resize(n);
for(int i=0;i<n;i++) cin>>point[i];
// 二分判定法找到最少的局数
int left=1,right=n;
while(left<=right) {
int middle=(left+right)>>1;
if(judge(n,k,middle)) right=middle-1;
else left=middle+1;
}
if(left>n) cout<<-1;
else cout<<left;
return 0;
}