二分的一道题

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

 



 

 

 
posted @ 2019-03-22 19:27  LightAc  阅读(107)  评论(0编辑  收藏  举报
返回顶端