zoukankan      html  css  js  c++  java
  • HDU3507 Print Article(斜率优化dp)

    前几天做多校,知道了这世界上存在dp的优化这样的说法,了解了四边形优化dp,所以今天顺带做一道典型的斜率优化,在百度打斜率优化dp,首先弹出来的就是下面这个网址:http://www.cnblogs.com/ka200812/archive/2012/08/03/2621345.html

    上面讲的很详细,但是实际上有些地方貌似是不小心写错了,所以我也来复述一下感悟一下收获。

    首先题意是比较明确的,如果我们定义dp[i]为打印到第i个字符时的最小花费的话,显然有下面的转移:

    dp[i]=dp[j]+(sum[i]-sum[j])^2+m

    然后我们考虑k<j<i时的情况,如果说我们求dp[i]的时候选择j比选择k更优,就会有:

    dp[j]+(sum[i]-sum[j])^2+m>dp[k]+(sum[i]-sum[k])^2+m

    然后化简就会有:

    (dp[j]+sum[j]^2)-(dp[k]-sum[k]^2)/2*(sum[j]-sum[k]) < sum[i] 

    然后左边的项看上去是非常像斜率的,所以我们可以定义一个g[j,k]=(dp[j]+sum[j]^2)-(dp[k]-sum[k]^2)/2*(sum[j]-sum[k])

    g[j,k]<sum[i]就表示了j点比k点更优。

    考虑a<b<c的情况  g[c,b]<g[b,a]的时候说明什么了呢??

    如果g[c,b]<sum[c]  那么 c比b更优

    如果g[c,b]>=sum[c],则g[b,a]>g[c,b]>=sum[c] 说明 a比b更优

    所以如果(c,b)的斜率<(b,a)的斜率那么 b点是不用考虑的。

    基于这一点我们可以用一个队列,像求凸包一样去维护可行的点集。由于g[c,b]<g[b,a]的情况不存在,所以只有g[c,b]>=g[b,a],因此点集应该是上凸的

    所以对于队列一开始的点集,如果队首元素的斜率g(que[qh+1],que[qh])<sum[i]的话,那么我们可以将队首元素弹出

    (其实一般情况下应该是不可以的,但由于sum[i]是递增的,所以在求dp[i]时有g(que[qh+1],que[qh])<sum[i],dp[i+1]也有g(que[qh+1],que[qh])<sum[i+1],因此队首的元素一定是不用考虑的)

    然后直到我们找到一个可行解。

    然后就将现在的元素插入队尾,插入队尾的时候就要维护下凸的性质,大概就是这样子。

    原博客讲的十分的清楚,然后评论里也讲了一些存在的纰漏和补充的地方,原博的下凸应该改为上凸吧,还有就是弹队首的时候还是要多加说明可能会更好。

    #pragma warning(disable:4996)
    #include <iostream>
    #include <cstdio>
    #include <vector>
    #include <algorithm>
    #include <cstring>
    #include <string>
    #include <cmath>
    using namespace std;
    
    #define ll long long
    #define maxn 510000
    
    ll dp[maxn];
    ll sum[maxn];
    ll a[maxn];
    int n, m;
    
    int que[maxn];
    int qh, qt;
    
    ll getup(int i, int j){
    	return (dp[i] + sum[i] * sum[i]) - (dp[j] + sum[j] * sum[j]);
    }
    
    ll getdown(int i, int j){
    	return 2 * (sum[i] - sum[j]);
    }
    
    int main()
    {
    	while (cin >> n >> m){
    		a[0] = sum[0] = 0;
    		for (int i = 1; i <= n; ++i){
    			scanf("%I64d", a + i);
    			sum[i] = sum[i - 1] + a[i];
    		}
    		dp[0] = 0;
    		qh = qt = 0;
    		que[qt++] = 0;
    
    		for (int i = 1; i <= n; ++i){
    			while (qh + 1 < qt && getup(que[qh + 1], que[qh]) <= getdown(que[qh + 1], que[qh]) * sum[i]){
    				qh++;
    			}
    			dp[i] = dp[que[qh]] + (sum[i] - sum[que[qh]])*(sum[i] - sum[que[qh]]) + m;
    			while (qh + 1 < qt && getup(i, que[qt - 1])*getdown(que[qt - 1], que[qt - 2]) <= getup(que[qt - 1], que[qt - 2])*getdown(i, que[qt - 1])){
    				qt--;
    			}
    			que[qt++] = i;
    		}
    		printf("%I64d
    ", dp[n]);
    	}
    	return 0;
    }
    
  • 相关阅读:
    虚函数和纯虚函数
    MS CRM 2011中PartyList类型字段的实例化
    MS CRM 2011的自定义与开发(12)——表单脚本扩展开发(4)
    MS CRM 2011的自定义与开发(12)——表单脚本扩展开发(2)
    MS CRM 2011的自定义和开发(10)——CRM web服务介绍(第二部分)——IOrganizationService(二)
    MS CRM 2011 SDK 5.08已经发布
    MS CRM 2011 Q2的一些更新
    最近很忙
    Microsoft Dynamics CRM 2011最近的一些更新
    补一篇,Update Rollup 12 终于发布了
  • 原文地址:https://www.cnblogs.com/chanme/p/3891049.html
Copyright © 2011-2022 走看看