太神了,專門寫一篇題解 qwq
簡要題意:給你 \(R\) 個紅球和 \(B\) 個藍球,你要把它們放到 \(K\) 個箱子裡,要求沒有兩個箱子完全相同(即兩種球個數就相同),求 \(K\) 的最大值。
設第 \(i\) 個箱子中有 \(x_i\) 個紅球,\(y_i\) 個藍球,就變成了找平面上一個大小最大的點集 \((x_i,y_i)\),使 \(\sum x_i =R, \sum y_i=B\)。進一步,由於可以直接將 \(x\) 最大的點 \(x\) 座標變大,\(y\) 同理,因此只需有 \(\sum x_i \le R, \sum y_i \le B\) 即可。
這是一道二維平面上的題,我們可以想辦法把它變成一維。給 \(x\) 方向賦一個權重 \(p\),\(y\) 方向賦一個權重 \(q\),那麼一個點 \((x,y)\) 就被投影到了 \(px+qy\) 上。此時我們發現所有點投影后的權重和為 \(\sum px_i+qy_i=p\sum x_i+q\sum y_i\),於是當 \(\sum x_i \le R, \sum y_i \le B\) 時,便有 \(\sum px_i+qy_i\le pR+qB\)。在某種程度上,我們就會希望 \(\sum px_i+qy_i\) 儘量小。
首先當然二分 \(K\),問題變為判定一個 \(K\) 是否可行。然後我們考慮一個凸包,凸包上的點 \((X,Y)\) 代表 \(\sum x_i=X\) 時,\(\sum y_i\) 的最小值為 \(Y\)。感性理解一下這玩意大概就是凸的,並且對每個 \(X\) 都有定義。於是 \(K\) 可行當且僅當點 \((R,B)\) 在凸包上方。又發現對於一個 \((p,q)\),使 \(p\sum x_i+q\sum y_i\) 最小時,\((\sum x_i,\sum y_i)\) 一定在凸包上,於是我們嘗試用 \((p,q)\) 搞出凸包上的一些點。
繼續發現 \(p\sum x_i+q\sum y_i=(p,q)\cdot (\sum x_i,\sum y_i)\),即向量 \((x_i,y_i)\) 在向量 \((p,q)\) 上的投影。\(p\sum x_i+q\sum y_i\) 最小,就是這個投影最小,可以看作拿一條與向量 \((p,q)\) 垂直的直線去切這個凸包,所以每個點都一定有機會被切到,且 \((p,q)\) 的斜率越大,切到的點越偏右。於是再對 \((p,q)\) 的斜率進行二分,如果發現求出來的點 \((\sum x_i,\sum y_i)\) 在 \((R,B)\) 左下方,那就成了;如果在 \((R,B)\) 右上方,那就寄了;如果在左上方,那就增大斜率;如果在右下方,那就減小斜率。
這裡有兩個技巧:1,不要在實數域上二分 \((p,q)\) 的斜率,令 \(p+q=10^9+7\)(或其它常數),然後直接二分 \(p\),可以發現這樣基本上能覆蓋到所有的斜率都能被弄到,從而能切到每個點。2,由於凸包上相鄰兩條線段斜率可能非常相近,因此我們要當發現當前凸包上一條連線在 \((R,B)\) 下方時直接返回合法。
最後的問題是如何計算對於一個 \((p,q)\) 計算 \(p\sum x_i+q\sum y_i\) 的最小值。我們二分一個 \(z\),求出 \(p\sum x_i+q\sum y_i\le z\) 的個數進行二分。然後求出 \(p\sum x_i+q\sum y_i\le z\) 的 \(x,y\) 分別的和以及多餘的一些 \(p\sum x_i+q\sum y_i=z+1\) 的前若干個 \(x,y\) 的和。以上操作全部用類歐做就是一個 \(\log\),或者發現如果我們選了一個點 \((x,y)\),那麼它左下角的所有點都一定已經被選了,所以有 \(\min(x,y)\le O(W^{1\over 3})\)(\(W\) 為值域),二維分別列舉即可。
一共三個二分,最後一步用類歐時間複雜度就 \(O(\log^4 W)\),直接列舉複雜度就 \(O(W^{1\over 3}\log^3 W)\)。