题意
给定(n)个点,以及(m),每个点向原点连有一条线段,你需要画(m)条直线,使得每个点的线段都存在某条线段经过(若该点为原点,则每条经过原点的直线都经过这条线段),求(m)条直线距离原点的最小值最大是多少。
(n,mle 10^5)
做法
二分答案(r),那么考虑圆心为原点半径为(r)的圆。
不应存在有点严格在圆的内部。
容易证明,我们选取的直线与圆相切一定不劣。
考虑每个点对圆的两个切点(有可能相同)的极角(l,r(lle r)),表示存在某条直线与圆切点的极角(in[l,r])。
然后我们将问题转化为
给定(n)个区间([l,r]),是否可以选取(m)个点,使得每个区间都包含至少一个点
如果这是在序列上做(注意该题的区间是在环上的),是存在经典的贪心:
选取右端点最小的一个区间,选择右端点,除去包含该点的区间,反复操作知道不存在区间。
而在环上,是不存在右端点最小的区间的(不存在偏序关系)。
引理:存在最优解,使得每个点都位于某个区间的右端点。
证明:
对于一种选点的方式,可以将每个点从所在位置向右移,知道位于某个区间的右端点,显然这并不会使某个原来有点的区间现在无点。
根据引理,可以枚举某个选了右端点的区间,然后以这个右端点作为数轴上(0)点,以右端点的大小定义偏序关系(特殊的,钦定该区间作为第一个区间),从而可以进行序列上的贪心,这样复杂度是(O(n^2logn))的。
考虑破环成链,按右端点排序,再将每个区间复制一遍,左右端点增加(2pi),注意这里是按右端点定义偏序关系,所以开始的区间要保证右端点(in[0,2pi))。(在实际代码中,可以忽略精度,取([0,2pi]))
我们枚举某个区间(in[1,n]),其右端点选了点,然后便是([i,i+n))作为序列来做贪心。
我们破环成链,虽然没有严格满足题意中的关系:可能有两点重合,但破环成链后这两点不为同一点。
但在右端点相同,且选了该点作为第一个点时,取这类区间的第一个区间,是包含了这个解的。
这样可以做到(O(n^2))。
注意到若我们已知选取了区间(i)的右端点,下一个贪心选取的区间(j(i<j))是确定的,故可以通过双指针的方式(O(n))确定下一个区间。再通过倍增得到选取区间(i)后,再选(2^k)个点所在的区间。
可以在(O(nlogn)-O(nlogn))的复杂度内,检查(forall iin[1,n])作为第一个区间的合法性。
总复杂度(O(nlognlogV))。