码迷,mamicode.com
首页 > 其他好文 > 详细

【Hdu3507】Print Article(斜率优化)

时间:2018-02-02 14:13:54      阅读:120      评论:0      收藏:0      [点我收藏+]

标签:tchar   队列   dpi   article   markdown   def   return   printf   algorithm   

Description

题意:给N个数,按顺序全部取走,每次取一段连续的区间,代价为\((S[i]-S[j])^2+M\)

其中M为一个给定的常数,\(S[i]\)为前缀和

\(N\leq 500000\)

Solution

常规的方程:\(dp[i]=min\{dp[j]+(S[i]-S[j])^2+M\}, j<i\)

\(O(n^2)\)是过不了50万的,用斜率优化

设有\(k<j<i\) 使得决策j更优,那么有

\(dp[j]+(S[i]-S[j])^2+M<dp[k]+(S[i]-S[k])^2+M\)

整理得 \(\frac{(dp[j]+S[j]^2)-(dp[k]+S[k]^2)}{(S[j]-S[k])}<2*S[i]\)

\(f[i]=dp[i]+S[i]^2\),所以有\(\frac{f[j]-f[k]}{s[j]-s[k]}<2*S[i]\)

此时决策j更优,反之决策k优

易证\(f[i]\)也单调递增,所以可用单调队列维护

Code

#include <cstdio>
#include <algorithm>
#define N 500010
#define squ(x) ((x)*(x))
using namespace std;

int n,M,l,r,q[N],s[N],dp[N];

inline int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}

inline int f(int k,int j){return dp[j]+squ(s[j])-(dp[k]+squ(s[k]));}
inline int g(int k,int j){return s[j]-s[k];}

void DP(){
    l=1,r=0;q[++r]=0;dp[0]=0;
    for(int i=1;i<=n;++i){
        while(l<r&&f(q[l],q[l+1])<=2*s[i]*g(q[l],q[l+1])) l++;
        int j=q[l];
        dp[i]=dp[j]+squ(s[i]-s[j])+M;
        while(l<r&&f(q[r],i)*g(q[r-1],q[r])<f(q[r-1],q[r])*g(q[r],i)) r--;//保证斜率单调
        q[++r]=i;
    }
}

int main(){
    while(~scanf("%d%d",&n,&M)){
        for(int i=1;i<=n;++i) s[i]=s[i-1]+read();
        DP();
        printf("%d\n",dp[n]);
    }
    return 0;
}

【Hdu3507】Print Article(斜率优化)

标签:tchar   队列   dpi   article   markdown   def   return   printf   algorithm   

原文地址:https://www.cnblogs.com/void-f/p/8404311.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!