二分的一道题
Examples
输入
5 8
2 3 1 1 2
输出
4
输入
7 10
1 3 4 2 1 4 2
输出
2
输入
5 15
5 5 5 5 5
输出
1
输入
5 16
5 5 5 5 5
输出
2
输入
5 26
5 5 5 5 5
输出
-1
Note
在第一个样例中,泰泰学长第一天可以喝第四杯咖啡(写1 页), 在第二天喝第一杯喝第二杯(写2 + (3 - 1) = 4 页), 第三天喝第五杯咖啡(写 2 页) 同时在第四天喝第三杯咖啡(写1 页) 所以答案是 4 . 显然没有其他方案能够在三天内写完或者用时更少.
在第一个样例中,泰泰学长第一天可以喝第三、四、二杯咖啡(写4 + (2 - 1) + (3 - 2) = 6 页), 在第二天喝第六杯(写4 页)所以答案是 2 . 显然泰泰学长不能够在一天写完.
在第三个样例中,泰泰学长第一天可以喝完所有的咖啡(写5 + (5 - 1) + (5 - 2) + (5 - 3) + (5 - 4) = 15 页).
在第四个样例中,泰泰学长不应该第一天可以喝完所有的咖啡,应该第二天喝其中的一杯咖啡. 所以在第一天泰泰学长写5 + (5 - 1) + (5 - 2) + (5 - 3) = 14 页 第二天写5 页.
在第五个样例中,泰泰学长就算是一天喝一杯咖啡也无法完成课程作业, 所以答案是-1.
#include <algorithm> #include <iostream> using namespace std; typedef long long ll; int power[2000010],m,n; bool cmp(ll a, ll b) { // 重构sort函数将大放在前面 return a > b; } int check(ll x) { int i,j = 0, flag = 0; //flag用于判断杯数所要减去的能量 ll ans = m; if(x <= 0) // 如果天数<=0那么就需要区间向右移动 return 0; //如果x天数可以做完作业,那么区间向左移动,判断更少的天数 while(ans > 0) { for(i = 1; i <= x; i++) { // 注 :相当于是让较大的值减去的值最少(所以从大到小)然后依次查看看第x天能否完成 如果第x天能完成那么 完成天数一定小于等于第x天 ans -= max(0, power[j++] - flag); //如果能量为负,就取0 if(j >= n) break; } flag++; if(j >= n && ans > 0) return 0; //如果n倍咖啡喝完,还是没有完成作业 } return 1; } int main() { int i; cin >> n >> m; for(i = 0;i < n;i++) // 输入测试值到数组中 cin >> power[i]; sort(power, power+n, cmp); // 将数组从大到小排序 int l = 0, r = n, mid, ans = -1; // l为左边界 r为有边界 mid 为中间值 初始化 ans 的值为 -1 // 算法基本思想天数不可能大于 n 天所以使用二分查找答案 while(l <= r) { // 当左边界值小于右边界值时一直进行循环 mid = (l+r) / 2; if(check(mid)) { //如果mid这天能完成 ans = mid; r = mid - 1; } else l = mid + 1; } //如果扫完一遍之后还是不能完成呢就输出 -1 if(check(ans)) // 这里需要判断二分得到的天数是否能完成,不能完成就输出-1 cout << ans << endl; else cout << -1 << endl; }
作者:LightAc
出处:https://www.cnblogs.com/lightac/
联系:
Email: dzz@stu.ouc.edu.cn
QQ: 1171613053
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。