wqs二分學習筆記
提出問題
在某些題目中,強制規定只能選\(k\) 個物品,選多少個和怎麼選都會影響收益,問最優答案。
演算法思想
對於上述描述的題目,大部分都可以通過列舉選擇物品的個數做到\(O(nk^2)\) 或\(O(nk)\) 的\(\mathrm{DP}\) ,如果沒有選擇個數的限制的話,複雜度大概會降為\(O(n)\) 級別。
先不考慮數量限制。
假設要最小化權值。
還是拿題說吧:給定長度為\(n\) 的正整數序列,要求將該序列劃分為\(k\) 段,記每段之和為\(sum(i)\) ,求最小的\(\sum\limits_{i=1}^k sum(i)^2\) 。
如果沒有段數限制,那我們肯定是每個數分成一段對吧。
如果加上段數限制呢?
先放上結論:
為縱座標,把這
\(n\)
個點放在平面直角座標系上,那麼形成的圖形會是一個上凸包。也就是相鄰兩點的斜率單調不增。
那就可以考慮\(\mathrm{wqs}\) 二分了。
注意當前的問題是:我們知道這個圖形是一個上凸包,但是並不知道具體的\((x,f(x))\) 座標。
我們可以二分一個權值\(mid\) ,這個\(mid\) 表示,我們要拿一條直線去切當前這個凸包,這個直線的斜率為\(mid\) 。因為是上凸包,那這條直線肯定會在交某個點\((x,f(x))\) 時截距取到最小值。設當前截距為\(g(mid)\) 。
直線可以表示成\(y=kx+b\) ,所以\(f(x)=mid\cdot x+g(mid)\) 。
移項,\(g(mid)=f(x)-mid\cdot x\) 。
觀察上面的等式,如果當前橫座標為\(x\) 的話,\(g(mid)\) 恰好是\(f(x)\) 減去\(x\) 個\(mid\) 。
\(f(x)\) 不好求,那我求出來\(g(mid)\) ,再順便求出來\(x\) 不就行了嗎。
也就是說,如果能求出截距\(g(mid)\) ,並且知道當前切到點的橫座標\(x\) ,那就可以求得\(f(x)\) ,並且可以根據\(x\) 和題目中的\(k\) 來調整\(mid\) 了。
回到題目,我們假設當前沒有分\(k\) 段這個限制,但是多了一個條件,每分一段都需要將代價額外加上\(mid\) 。
在這個條件下,我們做一遍沒有取物品限制的\(\mathrm{DP}\) ,得出當前的最優解\(a\) 和取最優解時候分出的段數\(b\) ,那就有\(g(mid)=a,x=b\) 。
這樣就能求出來\(f(x)\) 了。
但是關鍵不在\(f(x)\) ,而在這個\(x\) 。如果使用的這個\(x\) 大於題目中的\(k\) ,那就得增大這個\(mid\) ,感性理解一下,代價增多了分的段數才會少,反之就要減少\(mid\) 。
這樣通過二分就可以找到一條恰好切於\((k,f(k))\) 這個點的直線,進而就知道答案\(f(k)\) 了。
還有一個問題沒有解決,如果我們二分不出來這個具體的\(k\) 怎麼辦,也就是說,凸包上出現三點共線的情況怎麼辦。
如果這樣,我們就再額外新增一個規則,比如說在滿足\(g(mid)\) 為最大權值的情況下使得\(x\) 最小。這樣就知道直線的最左端點\(t\) 了。又因為斜率和截距是相同的,所以即使\(t!=k\) 拿截距\(g(t)-k\cdot mid\) 也還是最終的答案。
例題
[國家集訓隊2] Tree I
Description
給你一個無向帶權連通圖,每條邊是黑色或白色。讓你求一棵最小權的恰好有\(k\) 條白色邊的生成樹。題目保證有解。
Sol
這就是\(\text{wqs}\) 二分裸題了。二分一個\(mid\) ,然後把所有白邊的邊權加上\(mid\) ,然後求一下當前的花費和用了幾條白色邊,然後動態調整即可。
這裡有一個細節就是會出現白邊和黑邊邊權相等的情況,這時候就要用到上邊的做法,強制規定一個規則。假設我們規定相等時先用白邊,那二分就這麼寫:
while(l<=r){ int mid=l+r>>1;check(mid); if(used>=k) ans=mid,l=mid+1; else r=mid-1; }
關鍵在於是\(used>k\) 時記錄\(mid\) 還是在\(used<k\) 時記錄。
因為我們令\(x\) 儘可能大,所以要在\(used>=k\) 時記錄\(mid\) 。
[Luogu4983] 忘情
Description
定義一段序列的值為\(\frac{\left((\sum\limits_{i=1}^n x_i\times \bar x)+\bar x\right)}{\bar x^2}\) ,其中\(n\) 為該序列長度。
給定長度為\(n\) 的序列,要求分為\(m\) 段,使得每一段的值的和最小。
Sol
把這個式子拿出來推一推,發現這就是個斜率優化的式子了。
然後就套路二分\(mid\) ,\(\text{check}\) 的時候用斜率優化\(O(n)\) 求就行了。
md這題wa了好幾次竟因\(\mathrm{define}\) 沒加括號身敗名裂
[CF739E] Gosha is hunting
Description
有\(a\) 個寶貝球和\(b\) 個大師球。對於每個神奇寶貝,用寶貝球抓到的概率為\(p_i\) ,用大師球抓到的概率為\(q_i\)
。不能對一個神奇寶貝用多個相同種類的球,但是可以既用寶貝球又用大師球。問最優方案下期望抓到的神奇寶貝數量。
Sol
這題...因為有兩個限制,所以要\(\text{wqs}\) 套\(\text{wqs}\) 。
每次二分出\(mid1,mid2\) ,表示每使用一個寶貝球就要支付\(mid1\) 的代價,每使用一個大師球就要支付\(mid2\) 的代價,然後正常做\(\text{dp}\) ,記錄三個狀態:最優方案期望抓多少,最優方案下用多少寶貝球,最優方案下用多少大師球。然後轉移取最大值就好了。
一個小細節就是,如果同時用寶貝球和大師球,那期望不僅僅是\(p_i+q_i\) ,而應該是\(p_i+q_i-p_iq_i\) 。這個推一推式子就知道了。
[HEOI2018] 林克卡特樹
Description
給定一棵\(n\) 個節點帶邊權的樹,求\(k+1\) 條點不相交的鏈使得邊權和最大。\(k<n\leq 3\cdot 10^5\) 。
Sol
首先有個\(60\) 分做法,就是暴力樹形\(\text{DP}\) 。
通常設狀態都是\(f[i][j]\) 表示點\(i\) 為根的子樹,選了\(j\) 條鏈的最大邊權和。但是我們發現這並不能轉移。觀察到最終由選出來的鏈構成的圖上,每個點的度數只有\(0/1/2\) 三種,因此不妨將狀態變為\(f[i][j][0/1/2]\) 表示點\(i\) 為根的子樹,選了\(j\) 條鏈,現在點\(i\) 的度數為\(0/1/2\) 的最大邊權和。這樣就可以轉移了。
假設當前點為\(x\) ,剛\(\text{DP}\) 完\(x\) 的一個孩子\(y\) ,現在要進行揹包合併。
轉移根據取不取\((x,y)\) 這條邊分為兩種情況討論。
不取
設\(now=\max(f[y][k-i][0],f[y][k-i][1],f[y][k-i][2])\) ,讓\(x\) 的每個狀態和\(now\) 取個\(\max\) 就好了。
取
設\(d\) 為\((x,y)\) 的邊權。
這個分開看比較好:
\(f[x][k][1]=\max(f[x][k][1],f[x][i][0]+f[y][k-i][1]+d,f[x][i-1][0]+f[y][k-i][0]+d)\)
後邊兩項分別表示,從子樹\(y\) 中伸上來一條鏈然後連線上\(x\) ,或新建一條鏈,讓\((x,y)\) 單獨作為一條鏈的兩個端點。
\(f[x][k][2]=\max(f[x][k][2],f[x][i+1][1]+f[y][k-i][1]+d,f[x][i][1]+f[y][k-i][0]+d)\)
後邊兩項分別表示,讓\(x\) 作為一條鏈中間的某個點,即將從\(x\) 其他子樹伸上來的一條鏈和\(y\) 伸上來的一條連結在一起,或將\(y\) 直接與\(x\) 從其他子樹伸上來的一條鏈合併。
初值就是\(f[x][0][0]=f[x][1][1]=f[x][1][2]=0\) ,其他都為\(-\infty\) 。
後邊兩項表示,讓點\(x\) 作為一條向上延伸的鏈的最下方的端點,和讓\(x\) 單獨成為一條鏈。
這樣就可以通過\(O(nk^2)\) 的\(\text{DP}\) 拿到\(60\) 分了。
正解就是在此基礎上進行\(\text{wqs}\) 二分。
二分一個權值\(mid\) ,表示每選一條鏈就要付出\(mid\) 的代價。
然後進行沒有選出鏈數限制的樹形\(\text{DP}\) 。每個狀態\(f[i][0/1/2]\) 記錄兩個值,選出的最大邊權和與在此基礎上最多的鏈數。
然後二分就好了。
這裡也有在凸包上三點共線的問題,解決方案就是,因為我們最大化了選出的鏈數,所以在二分過程中,選出的鏈數如果\(>=k\) ,那就得記錄當前的\(mid\) 了。