一、最大化最小值
eg:poj 2456:疯牛
#include<stdio.h>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn = 1e7 + 10;
ll a[maxn];
ll n, c;
//对距离进行二分
int ans = 0;
int sum = 1;
int main()
{
cin >> n >> c;
for (int i = 1; i <= n; i++)
cin >> a[i];
sort(a + 1, a + 1 + n);
int l = 1;
int r = a[n];
ll mid = (l + r) / 2;
int sum;
int st;
int en;
while (r - l > 1)
{
sum = 1;
st = 1;
en = 2;
while (en <= n)
{
if (a[en] - a[st] >= mid) {
st = en;
sum++;
}
en++;
}
if (sum >= c) {
l = mid;
mid = (l + r) / 2;
}
else {
r = mid;
mid = (l + r) / 2;
}
}
ans = mid;
cout << ans << endl;
return 0;
}
二、最大化平均值
eg:有n个物品的重量和价值分别是wi和vi,从中选出k个物品使得单位重量价值最大。
样例(wi,vi)=(2,2) (5,2) (2,1)
解析:
这道题不能通过比较单位重量价值去计算,要利用二分思想。
设C(x)为单位重量的价值,满足C(x)>=x,如果x最大,则C(x)也必然最大,所以我们要做的是利用二分方法找到最大的x。
设w······wj是我们要找的那k个物品,则:
C(x)=(wi+···+wj)/(vi+···+vj)>=x
->wi+···+wj>=(vi+···+vj)*x
->wi+···+wj>=vi*x+···+vj*x
->(wi-vi*x)+···+(wj-vj*x)>=0
所以我们只要在0~INF内寻找满足上式合法的x,并且令x最大即可。
由于这是一个线性函数,所以利用二分去寻找最大的x。
三、尺取(二分特例)
eg:有一个长度为n的数列,一正整数S,求出一个长度最小的连续子序列,使它们的和>=S
样例:n=10,S=15;
a={5 1 3 5 10 7 4 9 2 8};
解析:定义一个sum=0,然后从左向右加,如果sum>S,则从左侧减,如果减完后发现sum<15,则从右侧加。
实现过程:sum=0 a[]=5 1 3 10 7 4 9 2 8 S=15
5
->右加 5 1 sum<15
->右加 5 1 3 sum<15
->右加 5 1 3 5 sum<15
->右加 5 ,1, 3, 5, 10 sum>15
->左减 1, 3, 5, 10 sum>15
->左减 3, 5, 10 ·······
->左减 5, 10
->左减 10
->右加 10, 7
->左减 7
->右加 7, 4
->右加 7, 4, 9
->左减 4, 9
``````
综上:只要sum>15就从左侧减,否则从右侧加
待更新······