

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;
}