HDU 4258 Covered Walkway(斜率优化DP)

10 篇文章 0 订阅
3 篇文章 0 订阅

题目链接

POJ 3709 K-Anonymous Sequence是完全类似的题目,只是状态方程变了而已。

dp[ i ] = min { dp[ j ] + (A[ i ] - A[ j + 1])*(A[ i ] - A[ j+1 ] ) + C  |  j<i }

单调队列维护下凸曲线。

记Y[ i ] = dp[ i ] + A[ i+1 ] *A[ i+1 ]   ,   X[ i ] = A[ i+1 ]

   rate( a, b) = (Y[b] - Y[a]) / (X[b] - X[a] )

 

"a<b && b不差于a"  即 " dp[ a ] + (A[ i ] - A[a+1])*(A[ i ] - A[a+1]) + C  >= dp[ b ] + (A[ i ] - A[b+1])*(A[ i ] - A[b+1]) + C "  整理得 "rate(a,b) <= 2*A[ i ] "

故有:

①   “a<b && b不差于a” 的等价条件是  :  rate(a , b ) <= 2*A[ i ]

②   最优决策点myque[p]具有性质:       rate(myque[p-1] , myque[p] )  <=  2*A[ i ]   <  rate(myque[p] , myque[p+1] )

      利用①筛选队首元素 。 利用②筛选队尾元素 , 其原理是 若rate(a,b)>=rate(b,c)   则rate(a,b) <= 2*A[ i ] < rate(b,c) 恒不成立,即b不可能最优。

代码:

#include <cstdio>
using namespace std;
const int maxn=1000050;
typedef long long LL;
LL A[maxn] ,dp[maxn] , C;
int myque[maxn] , head ,tail;
int N ;
#define Y(i) (dp[i]+A[i+1]*A[i+1])
#define X(i) (A[i+1])
bool head_check(int a,int b,int i){
    return Y(b)-Y(a) <= 2*A[i]*(X(b)-X(a));
}
bool tail_check(int a,int b,int c){
    return (Y(b)-Y(a))*(X(c)-X(b)) >= (Y(c)-Y(b))*(X(b)-X(a));
}
LL F(int j,int i){
    return dp[j] + (A[i]-A[j+1])*(A[i]-A[j+1]) + C ;
}
int main()
{
    while(scanf("%d%I64d",&N,&C)!=EOF && N+C){
        for(int i=1;i<=N;i++) scanf("%I64d",&A[i]);
        dp[0] = 0 ,myque[0] = 0 ,head = tail =0;
        for(int i=1;i<=N;i++){
            while(head < tail && head_check(myque[head],myque[head+1],i)) head++;
            dp[i] = F(myque[head],i);
            while(head < tail && tail_check(myque[tail-1],myque[tail],i)) tail--;
            myque[++tail] = i;
        }
        printf("%I64d\n",dp[N]);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值