带权二分
带权二分是一种DP优化方式(2D/XD问题转成1D/XD):
设 f [ i ] [ j ] f[i][j] f[i][j]表示状态 ( i , j ) (i,j) (i,j)的最优值(比如前 i i i个数分成 j j j组),那么枚举状态是 n 2 n^2 n2的,转移是 n X n^X nX的。
通过带权二分使得枚举状态是 n 1 n^1 n1的,转移是 n X ′ ( X ′ ≤ X ) n^{X'}(X'\leq X) nX′(X′≤X)的。
考虑去掉状态中第二维的限制,设 f [ i ] ′ = m a x ( f [ i ] [ j ] ) f[i]'=max(f[i][j]) f[i]′=max(f[i][j]),每次只用 f [ i ] ′ f[i]' f[i]′转移,也就是说对于每个 i i i,只取 f [ i ] [ j ] f[i][j] f[i][j]最优的 j j j。
假设最终状态是 f [ n ] [ m ] f[n][m] f[n][m],求出的 f ’ [ n ] f’[n] f’[n]所对应的最优解不一定是 m m m,所以我们考虑怎么让最后对应的最优解一定在 m m m上取得:
可以优化的前提是 f ′ f' f′最优化DP最后得到的 f [ n ] [ x ] f[n][x] f[n][x]得是个单峰的凸函数( y y y轴表示函数值 f [ n ] [ x ] f[n][x] f[n][x], x x x轴就是 x x x):
如上图, A A A是一个上凸函数, B B B是个下凸函数。
对于这样的凸函数,我们可以把 f ( x ) f(x) f(x)加上一个正比例函数 g ( x ) = k x g(x)=kx g(x)=kx变成 h ( x ) = f ( x ) + k x h(x)=f(x)+kx h(x)=f(x)+kx使得它的极值点左/右移( k k k越大,极值点越向 x x x正半轴方向移动)。
于是就二分这个 k k k,判断 h ( x ) = f ( x ) + m i d x h(x)=f(x)+midx h(x)=f(x)+midx的最优点与 m m m的关系。
最后 f [ n ] [ m ] = h ( n ) − m ⋅ k f[n][m]=h(n)-m·k f[n][m]=h(n)−m⋅k(减去 g ( x ) g(x) g(x))
具体来说,我们在用 f ′ ( i ) d p f'(i)dp f′(i)dp的时候,每次转移都额外的加上一个 k k k即可,因为一次转移表示第二维 x + 1 x+1 x+1,也就是 + k +k +k。
注意:
很多时候并不能刚好取到一个 k k k使得极值刚好取在 m m m,则需要就题目讨论一下到底怎么取(整数范围内,实数范围暂时不谈)。
例题
bzoj2654tree
这道题实际上算不上 D P DP DP,但确实用到了带权二分的思想。
考虑如果给每条百边加上一个额外的权值 k k k, k k k越大,最小生成树中白边就越少。
所以二分出一个 k k k,使得最小生成树上刚好有 n e e d need need条白边即可。
注意可能出现下面的情况:
二分出 m i d mid mid,这时最小生成树上有 > n e e d >need >need条白边,而取 m i d + 1 mid+1 mid+