三分法
Contents
介绍
三分法 (tenary search) 和 二分法(binary search) 类似,只不过三分法可以用于搜索一个 二次函数 的最值。
以搜索二次函数最值为例,假如有一个二次函数存在最大值。
要搜索这个最大值,可以令 $mid = \frac{l+r}{2}$,然后令 $lmid = mid - eps$,$rmid = mid + eps$,然后比较一下 $f(lmid)$ 和 $f(rmid)$ 的大小。
- $f(lmid) < f(rmid)$:最大值一定在 $[lmid, r]$ 之间。
- $f(lmid) > f(rmid)$:最大值一定在 $[l, rmid]$ 之间。
证明:假如 $f(lmid) < f(rmid)$,那么如果最大值在 $lmid$ 的左边则必然不可能,因为 $rmid$ 离最大值比 $lmid$ 更远。另外一种情况亦然。
例题
例1 洛谷P3382
题意
给定一个 $N$ 次函数,保证 $[l,r]$ 内存在一个点 $x$,使得 $[l,x]$ 单调增,$[x,r]$ 单调减,求 $x$
代码
#include <bits/stdc++.h>
using namespace std;
const double eps = (double)1e-7;
int n;
double l,r;
double arr[16];
double get(double x) {
double res = 0;
double cur = 1.0;
for (int i = 1; i <= n+1; i++) {
res += cur * arr[i];
cur *= x;
}
return res;
}
int main() {
cin >> n;
cin >> l >> r;
for (int i = n+1; i >= 1; i--) cin >> arr[i];
double low = l, high = r;
while (high - low > 5e-7) {
double mid = (low + high) * 0.5;
double lmid = mid - eps, rmid = mid + eps;
if (get(lmid) < get(rmid)) low = lmid;
else high = rmid;
}
printf("%.7f\n", low);
}
例2 CF1355E
题意
有 $N$ 个柱子,高度分别为 $h_1, h_2, … h_N$。现在有3种操作:
- 令一个柱子的高度+1,cost为 $A$
- 令一个柱子的高度-1,cost为 $R$
- 令一个柱子的高度+1,且令另外一个柱子的高度-1,cost为 $M$
求最小的cost使得所有柱子高度相等?
其中 $1 \leq N \leq 10^5, 0 \leq h_i \leq 10^9$
题解
如果我们枚举最终的高度 $h$,对于每一个 $h$ 都可以在 $\log(N)$ 的时间内计算出来对应的 $cost$。
然后我们会发现,随着 $h$ 的增加,$cost$ 是一个二次函数,具有一个最小值。(证明略)
所以就可以使用三分搜索了!
因为三分搜索的边界不太好处理,所以可以限定一个范围,在范围之内就停止搜索开始暴力枚举。
搜索的部分代码:
ll low = 1, high = 1e9;
while (high - low >= 10) {
ll mid = (low + high) >> 1;
ll lmid = mid-1, rmid = mid+1;
ll lv = solve(lmid), rv = solve(rmid);
if (lv > rv) low = lmid;
else high = rmid;
}
for (ll p = low; p <= high; p++) {
ll r = solve(p);
ans = min(ans, r);
}