显然min中的多项式λ(i,j)=−sump,jxi+sumxp,j+fj的值随j变化而变化的变化量不仅仅和j有关同样也和i有关,所以状态转移方程不能直接以单调队列优化。 但因为这个转移方程中的一些奇妙性质,我们就可以引入斜率优化将该算法的时间复杂度优化至O(n)。
所以我们需要用一个队列来维护凸包上的点集,并且要求队首的两个点的斜率大于等于S+sumT[i]S+sumT[i],对于每次求最小截距,队首的这个点一定就是我们需要点。 由于每个点只进队一次,也只出队一次,所以每次求j的均摊时间复杂度就是O(1)O(1),所以整个问题就在O(N)O(N)的时间内被解决了。
$calc$是按照上面的“斜率”定义来求斜率的函数$k[tl-1]$表示队列中$Q[tl-1]$与$Q[tl]$的斜率$ljl[i].w$就是$w[i]$辣。。。定义一个结构体而已。。。``` int hd=1,tl=0; for(int i=1;i<=n;++i) { while(hd<tl&&k[tl-1]>=calc(i,Q[tl]))--tl; k[tl]=calc(i,Q[tl]),Q...
枚举j即可 O(n) (斜率优化) 将min函数忽略 j的相关项移至等号左边 i与j的乘积项仍保留在右边 ts[ j ] + dp[ j ] = i * su[ j ]- i * su[ i - 1 ] + ts[ i - 1 ] - a[ i ] + dp[ i ] 可以发现 这是一个以i为斜率的一次函数 左边视为纵坐标 su[ j ]为横坐标 i即为斜率...
所以我们选择的点应该是斜率小于2*sum[i]的最大斜率的边的终点,大于2*sum[i]的最小边的起点。 优化 很显然,这么一波猛如虎的操作,并没有从根本上降低O(n2)的复杂度,所以接下来我们就要来走完从O(n2)到O(n)的距离。 然后,在这里,我们考虑如果要满足上述,要求,那么我们所选的点应该一定满足斜率的单调递...