zoukankan      html  css  js  c++  java
  • 二分的一道题

    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
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接,否则保留追究法律责任的权利。
  • 相关阅读:
    关于float和double类型能表示的数据范围和精度分析
    P2737 [USACO4.1]麦香牛块Beef McNuggets 数学题 + 放缩思想
    csu 1554: SG Value 思维题
    csu 1551: Longest Increasing Subsequence Again BIT + 思维
    Rasheda And The Zeriba Gym
    cpc,a wonderful concert
    hdu_3308 区间合并
    poj_3667线段树区间合并
    poj_2777线段树+位运算
    poj_3468,线段树成段更新
  • 原文地址:https://www.cnblogs.com/lightac/p/10580503.html
Copyright © 2011-2022 走看看