整数二分模板
while (left <= right)
{
int mid = (left + right) / 2;
if(check(mid)){
ans=mid;
left = mid + 1;
}
else right = mid - 1;
}
double二分模板
for(int i=0; i<100; i++)
{
double mid = (left + right) / 2;
if(check (mid)){
ans = mid;
left = mid;
}
else
right = mid;
}
while(fabs(right - left) > eps){
double mid = (left + right) / 2;
if(check (mid)){
ans = mid;
left = mid;
}
else
right = mid;
}
HDU2141
题解:
是否存在满足ai + bj + ck = x。ai + bj打包,二分找是否存在ck = x - ai - bj。
注意一些细节。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
int const N = 500 + 10;
ll a[N],b[N],c[N],x;
int l,n,m,p;
vector<ll>v; //注意用ll类型
int main(){
int caser = 0;
while(~scanf("%d%d%d",&l,&n,&m)){
printf("Case %d:\n",++caser);
v.clear();
for(int i=1;i<=l;i++) scanf("%lld",&a[i]);
for(int i=1;i<=n;i++) scanf("%lld",&b[i]);
for(int i=1;i<=m;i++) scanf("%lld",&c[i]);
for(int i=1;i<=l;i++)
for(int j=1;j<=n;j++)
v.push_back((ll)(a[i]+b[j]));
v.erase(unique(v.begin(),v.end()),v.end()); //去重
sort(v.begin(),v.end()); //每次都lower_bound()之前都忘记排序。。。
scanf("%d",&p);
while(p--){
scanf("%lld",&x);
bool flag = false;
for(int i=1;i<=m && !flag;i++){ //枚举c,对v进行二分
ll tmp = x - c[i];
int k = lower_bound(v.begin(),v.end(),tmp) - v.begin(); //find超时,因为不是二分查询
if(v[k] == tmp) flag = true;
}
if(flag) printf("YES\n");
else printf("NO\n");
}
}
return 0;
}
POJ3273
题解:
共n天,分成m组,要求花费最大的组值最小。类似于最大值最小化问题。我们可以二分枚举上限mid。max<=mid<=sum。
代码:
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <iostream>
#include <vector>
using namespace std;
int const N = 100000 + 10;
int a[N];
int n,m;
bool Judge(int limit){
int sum = 0,len = 0;
for(int i=1;i<=n;i++){
sum += a[i];
if(sum > limit){
sum = a[i];
len++;
}
}
if(++len > m) return false; //可能分的少于m组,但是每一组再分还是满足条件
else return true;
}
int main(){
while(~scanf("%d%d",&n,&m)){
int l = 0,r = 0;
for(int i=1;i<=n;i++){
scanf("%d",&a[i]);
r += a[i];
}
l = *max_element(a+1,a+1+n);
int mid;
while(l <= r){
mid = (l + r) >> 1;
if(Judge(mid)){ //如果找到了,找更小的
r = mid - 1;
}else{
l = mid + 1;
}
}
printf("%d\n",mid);
}
return 0;
}
POJ3528
题解:
最大化最小值。共有n个石头,给你石头到起点的距离,移走m块石头,使最小距离最大。
二分枚举最小距离mid。如果有小于这个距离的,那么移走石头,直到这个距离大于等于mid。
如果移走的石头大于m就不满足条件。
代码:
#include <cstring>
#include <algorithm>
#include <cstdio>
#include <iostream>
using namespace std;
typedef long long ll;
int const N = 50000 + 10;
int a[N],n,m,l;
bool Judge(int limit){ //判断限制的最短距离是否满足条件
int cnt = 0,i = 1,st = 0;
while(i <= n){
while(i <= n && a[i] - a[st] < limit) i++,cnt++;
st = i++;
if(cnt > m) return false;
}
return true;
}
int main(){
scanf("%d%d%d",&l,&n,&m); //n和m可能为0
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
a[++n] = l;
sort(a,a+n+1);
int left = 0,right = l,ans;
while(left <= right){ //枚举最短距离
int mid = (left + right) / 2;
if(Judge(mid)){
ans = mid;
left = mid + 1;
}else{
right = mid - 1;
}
}
printf("%d\n",ans); //left
return 0;
}