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