知识点讲解
伪代码如下:
视频链接:戳
结论:
如何设置蓝红边界:
一般流程:
二分查找
查找
#include<iostream>
#include<vector>
using namespace std;
int main()
{
int n,m;
cin >> n >>m;
vector<int > vec(n);
for(int i=0;i<n;i++){
cin >> vec[i];
}
while(m--){
int x;
cin >>x;
int l = -1, r = n;
while(r>l+1){
int mid = (r+l)>>1;
if(vec[mid]>=x){
r = mid;
}else{
l = mid;
}
}
if(vec[r]==x)cout << r+1 << " ";// 题目中的数组下标从1开始
else cout << -1 <<" ";
}
return 0;
}
二分答案
木材加工
#include <iostream>
#include <vector>
#include <cmath>
using namespace std;
long long int check(long long int mid, vector<long long int> vec, long long int n) {
long long int sum = 0;
for(int i=0;i<n;i++){
sum+=vec[i]/mid;
}
return sum;
}
int main() {
long long int n, k;
cin >> n >> k;
vector<long long int> vec(n);
for (int i = 0; i < n; i++) {
cin >> vec[i];
}
long long int l = 0, r = 100000000; // 表示木条长度的范围
while (l + 1 < r) {
long long int mid = (l + r) >> 1;
if (check(mid, vec, n) >= k) {//k为木条数量,check返回值>=k,说明切的太多段了,这样每段偏小
//-->应该让每段长一些
//-->左指针右移(l = mid)
l = mid;
} else {
r = mid;
}
}
if (l < 1)
cout << 0;
else
cout << l;
return 0;
}
- 一开始写的是:
while(l+1<r){
int mid=(l+r)/2;
if(ans_(mid,vec,n)>k){ //这里是>号
l=mid;
}else{
r=mid;
}
}
if(r<1)cout << 0;
else cout << r; //返回的是r
- 但发现结果是错的,所以改成 >=k,返回 L
- 哦,AC了,那就这样改喽,不管他啦,嘿嘿嘿
- 还有还有:
long long
yyds
砍树
再看一题:砍树
- 异曲同工。。。。
进击的奶牛
#include<iostream>
#include<vector>
#include<cmath>
#include<algorithm>
#define lld long long int
using namespace std;
lld check(lld mid, vector<lld>vec, lld n){
lld pre = vec[0]; // 先设置第一个数字,接下来需要找>=mid长度的区间,pre为区间的左坐标
lld sum = 0; // 记录满足的区间个数,最后牛牛的个数比区间个数多1
for(lld i=0;i<n;i++){ // 从区间的左坐标pre对应的数组下标0开始向右找区间
if(vec[i]-pre >= mid){ // 该区间满足
sum++;
pre = vec[i];
}
}
return sum+1;
}
int main(){
lld n,c;
cin >> n >> c;
vector<lld> vec(n);
for(lld i=0;i<n;i++){
cin >> vec[i];
}
sort(vec.begin(),vec.end());
lld l = -1,r = vec[n-1]-vec[0]+1; // 相邻两头牛的距离区间
while(l+1<r){
lld mid = (l+r) >> 1;
if(check(mid,vec,n) >= c){ // 如果check出来的牛比要求的多,说明牛牛相隔太近了,所以mid应该大一些,即l右移
l = mid;
}else{
r = mid;
}
}
cout << l;
return 0;
}
跳石头
好题:跳石头
好题解:ShawnZhou、Michael_Li
#include <iostream>
#include <vector>
#define lld long long int
using namespace std;
lld check(lld mid, vector<lld> vec, lld n) {
lld sum = 0, pre = 0; // pre表示选手所站的位置(石头)
for (lld i = 0; i <= n; i++) {
if (vec[i] - pre < mid) {// 如果所站的石头距离下一个石头的位置比mid小,那就把下一个石头移走
sum++;
} else {// 否则跳到下一个石头上
pre = vec[i];
}
}
return sum;
}
int main() {
lld ll, n, m;
cin >> ll >> n >> m;
vector<lld> vec(n + 1);
for (lld i = 0; i < n; i++) {
cin >> vec[i];
}
vec[n] = ll; // ll表示起点到终点的距离,那就把最后一个点也加进去
lld l = -1, r = ll + 1; // 跳跃距离
while (l + 1 < r) {
lld mid = (l + r) >> 1;
if (check(mid, vec, n) > m) { // m为要移走的石头个数,如果check出来的个数偏多,说明剩下的石头偏少,距离偏大
r = mid;// 所以应该少移一些石头,让mid减小
} else {
l = mid;
}
}
cout << l;
return 0;
}
- 一开始写的是:
lld l = 0; // 得按模板来l=-1 //木材加工里因为有限制最小为1,所以写l=0
lld r = ll; //得按模板来r=ll+1
while( l+1 < r){
lld mid= (l + r) >> 1;
if(check(mid, vec, n) >= m){ // 这里是>=
r = mid;
}else{
l = mid;
}
}
cout << r; // 这里是r
- 然后,改改就ok啦
卡牌
#include <iostream>
#include <vector>
#define lld long long
using namespace std;
lld check(lld mid, vector<lld> kapai, vector<lld> kongpai, lld n) {
lld sum = 0; // 空牌数
for (lld i = 0; i < n; i++) {
if (kapai[i] + kongpai[i] >= mid) {
sum += (mid - kapai[i]); // 表示要补的卡牌数
} else {
return -1; // 第i种牌都不够mid的数量,说明mid套牌肯定凑不齐
}
}
return sum;
}
int main() {
lld n, m;
cin >> n >> m;
vector<lld> kapai(n);
vector<lld> kongpai(n);
lld max = 0;
for (lld i = 0; i < n; i++) {
cin >> kapai[i];
if (kapai[i] > max)
max = kapai[i];
}
for (lld i = 0; i < n; i++) {
cin >> kongpai[i];
}
lld l = -1, r = max + 1;// 能得到的套牌的套数
while (l + 1 < r) {
lld mid = (l + r) >> 1;
lld return_kongpai = check(mid, kapai, kongpai, n);
if (return_kongpai >= m || return_kongpai == -1) { // m为提供空牌数
// 如果check的结果比给的空牌多,说明能组成的套牌过多了
// 所以套牌应该减少,即mid减少
r = mid;// 让套牌的右区间往左移动
} else {
l = mid;
}
}
cout << l;
return 0;
}