所谓二分法,在C++ STL中就一句话, l o w e r _ b o u n d lower\_bound lower_bound,但是写了几道题,发现真正使用的时候其实充满了技巧。
这两个问题其实联系很大,他们有着共同的思路,即
(1)将所要求的结果当做二分查找的对象,确定
[
l
,
r
]
[l,r]
[l,r]区间,
(2)确定某个
m
i
d
=
(
l
+
r
)
>
>
1
mid=(l+r)>>1
mid=(l+r)>>1是否是一个可行解,根据是否可行解更新
l
,
r
l,r
l,r的值,直到循环结束。
往往确定其是可行解的过程稍微复杂一点,但是理清思路可能并不是很难,直到我看到另一道题
一道常规又非常规的题
看到题的一瞬间greedy涌上我的心头,题解一看第一句话
我们只能保证单个物品的单位价值最大,但greedy不能保证多个物品加起来的单位价值最大。不妨再次考虑二分查找,将目标值:单位价值作为搜索目标,那么剩下的问题就是可行解的判断了,我们所要判断的是对于一个
m
i
d
mid
mid值,是否可以选择一个集合
S
\mathcal{S}
S,使得该集合的单位价值大于
m
i
d
mid
mid。如果可以,那么
l
=
m
i
d
l=mid
l=mid,否则
r
=
m
i
d
r=mid
r=mid。这样就将其完整的转化成了一个二分搜索问题。
难点:可行解的判断
∑
i
∈
S
v
i
/
∑
i
∈
S
w
i
≥
x
i
\sum_{i\in \mathcal{S}}v_i/\sum_{i\in \mathcal{S}}w_i\geq x_i
∑i∈Svi/∑i∈Swi≥xi
∑
i
∈
S
(
v
i
−
x
i
w
i
)
≥
0
\sum_{i\in \mathcal{S}}(v_i-x_iw_i)\geq 0
∑i∈S(vi−xiwi)≥0
也就是说只要保证集合
S
\mathcal{S}
S内所有的元素的
(
v
i
−
x
i
w
i
)
(v_i-x_iw_i)
(vi−xiwi)之和大于等于0即可,此时贪心是没有问题的,根据
(
v
i
−
x
i
w
i
)
(v_i-x_iw_i)
(vi−xiwi)将集合排序,只要前
k
k
k个物品满足此性质即可。