AtCoder Beginner Contest 263 G,Ex

G
如果我们不考虑\(A_{i}=1\)的情况,即不存在\(1+1=2\)这样的数对,那么剩下的质数都是奇数,而奇数+偶数=奇数。所以,若我们从\(i\)连一条边到\(j\),当且仅当\((A_{i}+A_{j})\)是质数,那么最后形成的图一定是二分图,(所有\(A_{i}\)为奇数的\(i\)在一侧,所有\(A_{i}\)为偶数的在另一侧)跑网络流就可以了。(注意这里同一类数不止一个,所以\(S\)连向\(i\)\(i\)连向\(T\)的边流量限制为\(b_{i}\)而不是\(1\)

那么现在如果有一个\(i\),满足\(A_{i}=1\),我们假设当前它自己和自己匹配了\(k\)对(\(0\leq k\leq \lfloor \frac{B_{i}}{2}\rfloor\)),那么将剩下的\(B_{i}-2k\)加入网络流中,假设当前最大流为\(maxflow\),那么我们总共匹配了\(f(k)=(maxflow+k)\)个数对。我们证明,\(f(k)\)是单峰的。

感性理解:
假设我们从\(A_{i}=1\)的点\(i\)向对面连去一些边\((i,to_{p})\),那么最优方案中这些边有的被选择了,有的没有。那么我们一开始肯定将没有匹配的(剩下的)\(1\),自己和自己匹配,这样能使答案加上\(1\);直到最后我们就会选择一些已经考虑的配对,那么此时我们要将两个已经配对的边拆散,组成一个新的配对的边——比如原本我们匹配了\((1,4)\)\((1,6)\)两个数对,那么我们现在拆散它们,组成\((1,1)\)这样新的一个,容易发现,这样会使答案减少\(1\)。故我们这个函数一定是一直向上升,到某个最高点后开始向下降。

那么我们三分,计算\(f(k=p1,p2)\)时的值即可。

https://atcoder.jp/contests/abc263/submissions/33863883

Ex
不难想到要先二分答案\(r\),之后问题转化成求有多少个交点在半径为\(r\)的圆内部。

发现一个结论:
在任意一处破环成链,将所有直线和圆的交点按照顺时针顺序离散化。如果离散化后,直线\(l1\)和圆的交点位置为\(P1,P2\)\(l2\)和圆的交点为\(P3,P4\)。那么\(l1\)\(l2\)的交点在圆的内部,当且仅当\(P1\leq P3\leq P2\leq P4\)

这样我们可以用线段树统计,具体实现见代码:

https://atcoder.jp/contests/abc263/submissions/33884586

说一点细节(这些细节让我调了很久):

  1. 实数二分尽量采用迭代若干次的方法,不要用while,否则eps设的太低容易死循环。
  2. 发现答案最大值不会超过\(3\times 10^6\),所以二分上界可以开小一点。
  3. 答案对精度要求不是很高,那么我们可以降低迭代次数优化时间复杂度。(计算几何常数是真的大)
  4. 记得count每次要清空所有的数组!
  5. 由于每个点与圆有两个交点,那么线段树的空间不能只开到maxn的四倍,要开到8倍!
posted @ 2022-08-08 22:32  Nastia  阅读(80)  评论(0)    收藏  举报