斜率优化

概念

优化形如 \(f_i=\min/\max\{f_j+a_i×b_j+c_i+d_j\}\)\(DP\) 方程,方程存在 \(i\)\(j\) 相乘的项。

设存在两个决策点 \(j,k\),且决策点 \(j\) 比决策点 \(k\) 更优,例如为取最小值时,得:

\[\large\begin{aligned} f_j+a_i×b_j+c_i+d_j&\leqslant f_k+a_i×b_k+c_i+d_k \\ (f_j+d_j)-(f_k+d_k)&\leqslant -a_i(b_j-b_k)\\ \frac{(f_j+d_j)-(f_k+d_k)}{b_j-b_k}&\leqslant -a_i \end{aligned} \]

\(DP\) 方程所对应的 \(x\)\(b_j\)\(y\)\(f_j+d_j\),斜率为 \(-a_i\)

这时若 \(-a,b\) 都递增,即 \(x\) 和斜率都递增,就可以用单调队列维护下凸包来来优化 \(DP\)

[ZJOI2007]仓库建设\(f_i=\min\limits_{j=0}^{i-1}\{f_j+dis_i×(p_i-p_j)-(s_i-s_j)+c_i\}\)

该方程所对应的 \(x\)\(p_j\)\(y\)\(f_j+s_j\),斜率为 \(dis_i\)

double x(int i)
{
    return p[i];
}
double y(int i)
{
    return f[i]+s[i];
}
double slope(int j,int k)
{
    return (y(j)-y(k))/(x(j)-x(k));
}

......

for(int i=1;i<=n;++i)
{
    while(h<t&&slope(q[h],q[h+1])<=dis[i]) h++;
    f[i]=f[q[h]]+dis[i]*(p[i]-p[q[h]])-(s[i]-s[q[h]])+c[i];
    while(h<t&&slope(q[t],i)<=slope(q[t],q[t-1])) t--;
    q[++t]=i;
}

初始化队列时为 \(h=0,t=1\),因为通常还需放入决策初始点 \(0\),所以可以直接 \(h=t=0\)。凸包内至少有两个点,所以判定时为 \(h<t\)

\(x\) 相同时,要注意返回正无穷还是负无穷。

单调性的处理

关于 \(x\) 和斜率 \(k\) 单调性不同时的不同处理方法。

\(x\) 单调,\(k\) 单调,单调队列维护。

\(x\) 单调,\(k\) 不单调,凸包上二分。[SDOI2012]任务安排

\(x\) 不单调,\(k\) 不单调,\(CDQ\) 分治或平衡树维护。[NOI2007]货币兑换

一些特殊的 \(DP\) 方程也可以用李超线段树来维护。[CEOI2017]Building Bridges

posted @ 2020-01-22 20:55  lhm_liu  阅读(227)  评论(0编辑  收藏  举报