HDU 4258 斜率优化dp

Covered Walkway

Time Limit: 30000/10000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 1496    Accepted Submission(s): 602

Problem Description

Your university wants to build a new walkway, and they want at least part of it to be covered. There are certain points which must be covered. It doesn’t matter if other points along the walkway are covered or not. 
The building contractor has an interesting pricing scheme. To cover the walkway from a point at x to a point at y, they will charge c+(x-y)2, where c is a constant. Note that it is possible for x=y. If so, then the contractor would simply charge c
Given the points along the walkway and the constant c, what is the minimum cost to cover the walkway?

Input

There will be several test cases in the input. Each test case will begin with a line with two integers, n (1≤n≤1,000,000) and c (1≤c≤109), where n is the number of points which must be covered, and c is the contractor’s constant. Each of the following n lines will contain a single integer, representing a point along the walkway that must be covered. The points will be in order, from smallest to largest. All of the points will be in the range from 1 to 109, inclusive. The input will end with a line with two 0s.

Output

For each test case, output a single integer, representing the minimum cost to cover all of the specified points. Output each integer on its own line, with no spaces, and do not print any blank lines between answers. All possible inputs yield answers which will fit in a signed 64-bit integer.

Sample Input

10 5000

1
23
45
67
101
124
560
789
990
1019

0 0

Sample Output

30726

Source

The University of Chicago Invitational Programming Contest 2012

题意:

有n个点需要被覆盖,覆盖第j到第i之间的点的花费是c+(x[i]-x[j])^2,问把所有的点都覆盖的最小花费。

输入n,c

输入n个点x[1...n]

当输入0 0时结束

代码:

//有状态转移方程dp[i]=min(dp[j]+C+(a[i]-a[j+1])*(a[i]-a[j+1])),数据是1e6的两重循环必然不行
//设k<j<i,当到达i点时如果从j点转移到i比从k点转移到i更优则有:dp[j]+C+(a[i]-a[j+1])^2<dp[k]+C+(a[i]-a[k+1])^2
//展开得:(dp[j]-dp[k]+a[j+1]^2-a[k+1]^2)/2*(a[j+1]-a[k+1])<a[i].其中a[i]常量(实现时是一重循环枚举i点),
//我们设yj=dp[j]+a[j+1]^2,xj=a[j+1] =>(yj-yk)/2*(xj-xk)<a[i].左边是计算斜率的式子。我们用一个单调队列
//来存储能够转移到i点状态的点并且队头是转移到i点状态的最优的解,每次要保持队头是最优解就要根据
//(yj-yk)/2*(xj-xk)<a[i]用队头去和队列中第二个去比较(如果队头不优于第二个就要删去队头元素)。
//设g[i,j]表示直线j-i的斜率,如果有g[k,j]>g[i,j]那么j点永远不可能是i的最优解,因为:
//我们假设g[i,j]<a[i],那么就是说i点要比j点优,排除j点。如果g[i,j]>=a[i],那么j点此时是比i点要更优,
//但是同时g[j,k]>g[i,j]>sum[i]。这说明还有k点会比j点更优,同样排除j点。排除多余的点,这便是一种优化!
//其实就是维护一个斜率递增的(下凸上凹)的图形。因此要把i点加入队列之前先判断是否能够维护斜率递增如果
//不能就把队列最后一个元素删掉直到是斜率递增的然后加入i点。
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
const int maxn=1000009;
int n,m,que[maxn];
ll dp[maxn],a[maxn];
ll getdp(int i,int j){
    return dp[j]+m+(a[i]-a[j+1])*(a[i]-a[j+1]);
}
ll getup(int j,int k){
    return dp[j]-dp[k]+a[j+1]*a[j+1]-a[k+1]*a[k+1];
}
ll getlow(int j,int k){
    return 2*(a[j+1]-a[k+1]);
}
int main()
{
    while(scanf("%d%d",&n,&m)&&(n+m)){
        for(int i=1;i<=n;i++) scanf("%lld",&a[i]);
        int head=0,tail=0;
        dp[0]=0;
        que[tail++]=0;
        for(int i=1;i<=n;i++){
            while(head+1<tail&&getup(que[head+1],que[head])<=a[i]*getlow(que[head+1],que[head]))
                head++;
            dp[i]=getdp(i,que[head]);
            while(head+1<tail&&getup(que[tail-1],que[tail-2])*getlow(i,que[tail-1])>=getup(i,que[tail-1])*getlow(que[tail-1],que[tail-2]))
                tail--;
            que[tail++]=i;
        }
        printf("%lld\n",dp[n]);
    }
    return 0;
}
时间: 2024-10-12 13:24:19

HDU 4258 斜率优化dp的相关文章

hdu 3669(斜率优化DP)

Cross the Wall Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 327680/327680 K (Java/Others)Total Submission(s): 4479    Accepted Submission(s): 812 Problem Description “Across the Great Wall, we can reach every corner in the world!” Now the

Fxx and game hdu 5945 斜率优化dp

dfs你怕是要爆炸 考虑dp; 很容易想到 dp[ i ] 表示到 i 时的最少转移步数: 那么: dp[ i ]= min( dp[ i ],dp[ i-j ]+1 ); 其中 i-t<=j<=i; 当 i%k==0时 ,dp[ i ]=min( dp[ i ],dp[ i/k ]+1 ): 很明显这种要T到飞起: 我们要优化dp: 1e6的数据考虑O(n)级别的: 斜率优化: #include<iostream> #include<cstdio> #include&

HDU 3507(斜率优化dp

题目:每次选取连续的若干数字的代价 要求选取虽有数字的最小代价. 思路:基础斜率dp题,题解见http://www.cnblogs.com/kuangbin/archive/2012/08/26/2657650.html /* * @author: Cwind */ #pragma comment(linker, "/STACK:102400000,102400000") #include <iostream> #include <map> #include &

HDU 3507斜率优化dp

Print Article Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)Total Submission(s): 12185    Accepted Submission(s): 3733 Problem Description Zero has an old printer that doesn't work well sometimes. As it is antiqu

hdu 2993 MAX Average Problem (斜率优化dp入门)

MAX Average Problem Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 5855    Accepted Submission(s): 1456 Problem Description Consider a simple sequence which only contains positive integers as

Print Article hdu 3507 一道斜率优化DP 表示是基础题,但对我来说很难

Print Article Time Limit: 9000/3000 MS (Java/Others)    Memory Limit: 131072/65536 K (Java/Others)Total Submission(s): 4990    Accepted Submission(s): 1509 Problem Description Zero has an old printer that doesn't work well sometimes. As it is antique

HDU 2829 Lawrence (斜率优化DP或四边形不等式优化DP)

题意:给定 n 个数,要你将其分成m + 1组,要求每组数必须是连续的而且要求得到的价值最小.一组数的价值定义为该组内任意两个数乘积之和,如果某组中仅有一个数,那么该组数的价值为0. 析:DP状态方程很容易想出来,dp[i][j] 表示前 j 个数分成 i 组.但是复杂度是三次方的,肯定会超时,就要对其进行优化. 有两种方式,一种是斜率对其进行优化,是一个很简单的斜率优化 dp[i][j] = min{dp[i-1][k] - w[k] + sum[k]*sum[k] - sum[k]*sum[

HDU 3507 Print Article(斜率优化DP)

题目链接 题意 : 一篇文章有n个单词,如果每行打印k个单词,那这行的花费是,问你怎么安排能够得到最小花费,输出最小花费. 思路 : 一开始想的简单了以为是背包,后来才知道是斜率优化DP,然后看了网上的资料,看得还挺懂的,不过我觉得如果以后真遇到斜率DP,要推起来肯定不简单..... 网上资料1 网上资料2 1 #include <iostream> 2 #include <stdio.h> 3 4 using namespace std; 5 6 int q[500005],dp

斜率优化DP总结

前言: 也是好久没有写题解了,最近主要学习了单调栈单调队列以及斜率优化DP这几个知识点,对于较难的斜率优化DP,做个小小的总结吧. 正(che)文(dan): T1 hdu 3507 在一个风和日丽的早上,你打开了网页,点进了hdu,偶然间看到了这道题,不屑的以为这仅仅是一个很水的DP,2分钟给出DP方程式,很快的写完后发现n的范围居然是500000,这让已经推出来的 O(n2)复杂度的递推式情何以堪,所以就产生了一种高逼格的优化方式:斜率优化. 这道题的方程式是什么呢? dp[i]=min(d