HDU-3507 Print Article 斜率优化DP

来源:互联网 发布:json 数据格式 编辑:程序博客网 时间:2024/05/17 22:35

大家都很强, 可与之共勉。

%%%大神LWD (YSY)
http://blog.csdn.net/BerryKanry/article/details/71773808

题意,给出一个数组,将其分为几组,每一组算出其和的平方加上给定数m,将每一组的值求和然后输出,求最小值。
提意明确,列出状态转移方程:
f[i]=f[j]+m+(sum[i]-sum[j])^2
注意,这个方程并不能用单调队列解决,因为i的决策不仅取决于j,还取决于(sum[i]-sum[j])^2,这就无法对f进行单调队列保存。
对方程进行数学处理,假定j和k,在决策i时,j比k优:
dp[j]+m+(sum[i]-sum[j])^2<dp[k]+m+(sum[i]-sum[k])^2
直接打开消元得出:
dp[j]+sum[j]^2-2*sum[i]*sum[j]< dp[k]+sum[k]^2-2*sum[i]*sum[k]
移项相除得:
dp[j]+sum[j]^2-(dp[k]+sum[k]^2)/2*(sum[j]-sum[k])<sum[i]
仔细一看的话,左边就是一个只关于j,k的斜率表达式了。定义左边为g(j,k)<sum[i]的话,说明在决策i时,j比k优,那么可以单调队列来维护斜率,最小的斜率最优且在对首。
为什么可以这样呢?再解释一遍。
因为我们发现,在比较决策i时的前驱决策j,k谁优时,得到了一个关乎斜率的等式g(j,k),g(j,k)<sum[i]时,说明j比k优,就是说,凡是斜率比g(j,k)小,那一定没有sum[i]大,如g(a,b)<g(b,c)<g(c,d)….<g(j,k)<sum[i],那就是a没有b优,b没有c优。。。如果用单调斜率的队列,就可以瞬间排除j以前的选项,排除选项,即为优化。
现在我们的单调队列维护的就是斜率的单调递增了,在决策i时,凡是对首斜率比sum[i]小的,都可以直接弹出去,因为不优,如上解释,每次队首一定是最优的,因为后面的都大于sum[i]了,不满足g(h,h+1)

#include "cstdio"int s[500010], dp[500010], q[500010], fr, tl, n, m;inline int Xval(int j, int k)  {    return (s[j] - s[k]) << 1;}inline int Yval(int j, int k)  {    return dp[j] + s[j] * s[j] - dp[k] - s[k] * s[k];}int main()  {    register int i;    while(~scanf("%d%d", &n, &m))  {        fr = tl = 0;        q[tl] = 0;        for(i = 1; i <= n; ++i)  scanf("%d", s + i);        for(i = 2; i <= n; ++i)  s[i] += s[i - 1];        for(i = 1; i <= n; ++i)  {            while(fr < tl && Yval(q[fr + 1], q[fr]) <= s[i] * Xval(q[fr + 1], q[fr])) ++fr; // k is better than j;            dp[i] = dp[q[fr]] + m + (s[i] - s[q[fr]]) * (s[i] - s[q[fr]]);            while(fr < tl && Yval(i, q[tl]) * Xval(q[tl], q[tl - 1]) <= Yval(q[tl], q[tl - 1]) * Xval(i, q[tl]))  --tl;            q[++tl] = i;        }        printf("%d\n", dp[n]);    }}
0 0
原创粉丝点击