二分答案题目列表

二分答案的一个模板,之后都用这两个模板:(要看数据是往哪个方向去偏的),具体题目具体分析

你要看等号的条件往哪个方向偏,那个等号能不能取到

  • 模板一:中间值往右偏向
      while(l < r) {
            //注意这里的mid 是往右取得的,所以之后要往左靠的,只是需要在等号的时候判断一下
            int mid = (l + r + 1)/2;
            if(条件检查) {
                l = mid;
            }else{
                r = mid - 1;
            }
        }
        cout << l;
    
  • 模板二: 中间值往左偏
      while(l < r) {
            //注意这里的mid 是往右取得的,所以之后要往左靠的,只是需要在等号的时候判断一下
            int mid = (l + r)/2;
            if(条件检查) {
                l = mid + 1;
            }else{
                r = mid;
            }
        }
        cout << r - 1;
    

分巧克力

https://www.luogu.com.cn/problem/P8647

  • 代码
#include<iostream>
#include<algorithm>
using namespace std;
const int MAX = 1e5;
int N, K;
int nums[MAX + 1][2];

int check(int H) {
    int ans = 0;
    for(int i = 0; i < N; i++) {
        ans += (int)(nums[i][0]/H) * (int)(nums[i][1]/H);
    }
    return ans;
}

int main() {
    cin >> N >> K;
    int maxlen = -1;
    for(int i = 0; i < N; i++) {
        cin >> nums[i][0] >> nums[i][1];
        maxlen = max<int>(nums[i][0], max<int>(nums[i][1], maxlen));
    }
    int l = 1, r = maxlen;
    while(l < r) {
        int mid = (l + r + 1)/2;
        if(check(mid) >= K) {
            l = mid;
        }else {
            r = mid - 1;
        }
    }
    cout << l;
    return 0;
}

跳石头

https://www.luogu.com.cn/problem/P2678

  • 代码
    #include<iostream>
    using namespace std;
    typedef long long ll;
    
    int N, M;
    ll L;
    ll nums[500005];
    
    int check(int minDis) {
      int ans = 0;
      int slow = 0, fast = 1;
      for(;fast <= N; fast++) {
          if(nums[fast] - nums[slow] < minDis) {
              ans++;
          }else{
              slow = fast;
          }
      }
      return ans;
    }
    
    int main() {
      cin >> L >> N >> M;
      nums[0] = 0;
      for(int i = 1; i <= N; i++) {
          cin >> nums[i];
      }
      nums[N + 1] = L;
      int l = 0, r = L;
      while(l < r) {
          int mid = (l + r + 1)/2;
          if(check(mid) <= M) {
              l = mid;
          }else{
              r = mid - 1;
          }
      }
      cout << l;
    
      return 0;
    }
    

技能提升

https://www.lanqiao.cn/problems/2129/learning/?page=1&first_category_id=1&sort=students_count&problem_id=2129

  • 解释:
    当使用的是暴力加优先队列的方法的时候,只能通过60%的案例,所以大顶堆不是最优的方法,要使用更为有效的二分答案算法
  • 暴力+优先队列:
    #include <iostream>
    #include <vector>
    #include <queue>
    using namespace std;
    typedef pair<int, int> pei;
    const int MAXL = 1e5;
    
    int N, M;
    pei nums[MAXL];
    priority_queue<pei> yq;
    
    long long ans;
    int main()
    {
      // 请在此输入您的代码
        cin >> N >> M;
        for(int i = 0; i < N; i++) {
            cin >> nums[i].first >> nums[i].second;
            yq.push(pei{nums[i].first, nums[i].second});
        }
    
        for(int i = 0; i < M; i++) {
            if(yq.top().first < 0) {
                ans += 0;
            }else{
                pei top = yq.top();
                yq.pop();
                ans += top.first;
                top.first -= top.second;
                yq.push(top);
            }
            
        }
    
        cout << ans;
    
        // while(!yq.empty()) {
        //     pei top = yq.top();
        //     cout << top.first << top.second << endl;
        //     yq.pop();
        // }
        return 0;
    }
    

分组

https://www.lanqiao.cn/problems/5129/learning/?contest_id=144

  • 代码:
    #include <iostream>
    #include <algorithm>
    #include <string>
    using namespace std;
    
    int n, k;
    int nums[10000004];
    
    int check(int x) {
        int cs = 0;
        int slow = 0, fast = 0;
        while(fast < n) {
            while(nums[fast] - nums[slow] <= x && fast < n) {
                fast++;
            }
            cs++;
            slow = fast;
        }
        return cs;
    }
    
    
    
    
    int main()
    {
        // 请在此输入您的代码
        //分组,使用的是加点的方式,要想极差最小,那么要先排序
        cin >> n >> k;
        for(int i = 0; i < n; i++) {
            cin >> nums[i];
        }
        sort(nums, nums + n);
        int l = 0, r = nums[n - 1] - nums[0];
        while(l < r) {
            int mid = (l + r) / 2;
            if(check(mid) > k) {
                l = mid + 1;
            }else{
                r = mid;
            }
        }
        
        cout << l;
        return 0;
    }
    
posted @ 2023-09-07 22:53  铜锣湾陈昊男  阅读(21)  评论(0)    收藏  举报