二分答案题目列表
二分答案的一个模板,之后都用这两个模板:(要看数据是往哪个方向去偏的),具体题目具体分析
你要看等号的条件往哪个方向偏,那个等号能不能取到
- 模板一:中间值往右偏向
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; }
技能提升
- 解释:
当使用的是暴力加优先队列的方法的时候,只能通过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; }

浙公网安备 33010602011771号