【算法-基础】二分答案(Binary Search)
引入
前置知识:二分搜索。
定义
二分答案是在二分搜索基础上扩展的算法。
对于纯的朴素算法,枚举 \(n\) 个可能的答案再进行判断(复杂度 \(O(m)\)),复杂度是 \(O(nm)\) 的,而二分的应用可以将其降低至 \(O(\log n \cdot m)\)。
大致的应用条件是:
- 答案在一个固定的有限区间内;
- 容易判断一个值是否符合条件;
- 区间呈现单调性。
具体实现
对照普通的二分查找——我们在判断一个数是否能作为答案时是判断了它的大小,而在二分答案中只需将这种判断改为一个判断函数即可。
与二分查找相同,二分答案也需要在有序数列内进行。
应用
- 朴素算法优化
通常可以使 \(O(n)\) 的时间复杂度变为 \(O(\log n)\)。
- 最大值最小化/最小值最大化
(二分答案大概就这一个正经用处(((
其实在一个范围内可行的 最大值/最小值 和这个是一个做法。
因为大部分要查找的答案就是这个:
\[\begin{matrix}
\Large\text{代价较低} \qquad \qquad \qquad \quad \Large\text{代价较高} \\
\Large\downarrow \qquad \qquad \qquad \qquad \qquad \Large\downarrow \\
\Huge\colorbox{red}{不合法解 } \Huge\colorbox{blue}{合法解 } \\
\qquad \; \Large\uparrow \\
\qquad \; \Large\text{答案}
\end{matrix}
\]
当当前答案为合法解,就将该值保留在区间内,再向更严格的区间内二分,否则将其排除出区间,向更松弛的区间内二分。
二分一般是直接对答案二分。
将花费作为二分对象,再判断使用这个花费能否使每个月都足够。
点击查看代码
/*
compiling in hszxoj
standard c++14
ide vscode
g++ test.cpp -o test && ./test
*/
#include <bits/stdc++.h>
#include <bits/extc++.h>
namespace {
#define filein(x) freopen(x".in", "r", stdin)
#define fileout(x) freopen(x".out", "w", stdout)
#define file(x) filein(x), fileout(x)
using namespace std;
using namespace __gnu_pbds;
#define ll long long
#define db double
#define un unsigned
#define ui un int
#define ull un ll
#define udb un db
template <typename T>
using pr = pair<T, T>;
#define pii pair<int>
#define pll pair<ll>
#define pdb pair<db>
#define fir first
#define sec second
#define mp(x, y) make_pair(x, y)
const int man = 1e5+10;
}
int n, m;
int a[man];
bool check (int x) {
int cnt = 1, p = 0;
for (int i = 1; i <= n; ++ i) {
if (p+a[i] > x) ++ cnt, p = 0;
p += a[i];
if (cnt>m || a[i]>x) return 0;
} return 1;
}
void pre () ;
int main () {
pre();
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; ++ i) scanf("%d", a+i);
int l = 1, r = 1e9, mid;
while (l < r) {
mid = (l+r)>>1;
// printf("%d %d |%d\n", l, r, mid);
if (check(mid)) r = mid; // 由于这个 mid 可行,所以 r 保留它;
else l = mid+1; // 这个 mid 不可行,所以不保留.
} printf("%d", (l+r)>>1); // 注意这行:需要最后再重新运算一下 mid.
return 0;
}
void pre () {
#ifndef ONLINE_JUDGE
file("test");
#endif
return ;
}
// ---

浙公网安备 33010602011771号