hdu3507(斜率dp)

来源:互联网 发布:耐克淘宝官方旗舰店 编辑:程序博客网 时间:2024/06/05 08:52

链接:点击打开链接

题意:给出n个数,要求按顺序全部取出,每次取出一段所花费的费用为取出一段数的和的平方加m,问最小费用是多少

代码1:

#include <stdio.h>#include <string.h>#include <stdlib.h>#include <iostream>#include <algorithm>using namespace std;const int INF=0x3f3f3f3f;int a[500005],q[500005],dp[500005];int in(int k1,int k2,int ai){    int x1,x2;    x1=dp[k2]-dp[k1]+a[k2]*a[k2]-a[k1]*a[k1];    x2=2*ai*(a[k2]-a[k1]);    if(x1<=x2)    return 1;    return 0;}int out(int k1,int k,int k2){    int x1,x2;    x1=(dp[k]-dp[k1]+a[k]*a[k]-a[k1]*a[k1])*(a[k2]-a[k]);    x2=(dp[k2]-dp[k]+a[k2]*a[k2]-a[k]*a[k])*(a[k]-a[k1]);    if(x1>=x2)    return 1;    return 0;}int main(){                                     //dp[i]表示输出到第i位的最小费用    int n,m,i,l,r,k,k1,k2,cas;                  //因此很容易推出dp[i]=min(dp[i],dp[j]+(sum[i]-sum[j])^2+m)    while(scanf("%d%d",&n,&m)!=EOF){            //但是复杂度为O(n^n),一定会超时,        for(i=1;i<=n;i++)        scanf("%d",&a[i]);                      //假设j<k,假设k优于j        for(i=2;i<=n;i++)                       //dp[k]+(sum[i]-sum[k])^2+m<dp[j]+(sum[i]-sum[j])^2+m        a[i]+=a[i-1];                           //G[j,k]=((dp[k]+sum[k]^2)-(dp[j]+sum[j]^2))/(2*sum[j]*(sum[k]-sum[j]))<=1时        memset(dp,0,sizeof(dp));                //假设成立,也就是k优于j,否则j优于k        l=r=0;                                  //当k1<k<k2时,G[k1,k]>=G[k,k2]时,k没有用处        q[0]=0;                                         for(i=1;i<=n;i++){        while(r-l>0){            k1=q[l],k2=q[l+1];            if(in(k1,k2,a[i]))            l++;            else            break;        }        dp[i]=dp[q[l]]+(a[i]-a[q[l]])*(a[i]-a[q[l]])+m;        while(r-l>0){            k1=q[r-1],k=q[r],k2=i;            if(out(k1,k,k2))            r--;            else            break;        }        q[++r]=i;        }        printf("%d\n",dp[n]);    }    return 0;}

代码2:

#include <math.h>#include <vector>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <iostream>#include <algorithm>using namespace std;long long sum[500005],que[500005];long long a[500005],q[500005],dp[500005];long long getx(long long x){    return 2*sum[x];}long long gety(long long x){    return dp[x]+sum[x]*sum[x];}long long cross(long long x1,long long y1,long long x2,long long y2,long long x3,long long y3){    return (y3-y1)*(x2-x1)-(y2-y1)*(x3-x1);}int main(){    long long i,k,n,m,head,tail;    while(scanf("%I64d%I64d",&n,&m)!=EOF){        sum[0]=0;        for(i=1;i<=n;i++){            scanf("%I64d",&a[i]);            sum[i]=sum[i-1]+a[i];        }        memset(dp,0,sizeof(dp));        head=tail=0;        q[tail++]=0;        for(i=1;i<=n;i++){            k=sum[i];            while((head+1<tail)&&((gety(q[head+1])-gety(q[head]))<=k*(getx(q[head+1])-getx(q[head]))))            head++;            dp[i]=gety(q[head])-k*getx(q[head]);            dp[i]+=sum[i]*sum[i]+m;            while((head+1<tail)&&cross(getx(q[tail-2]),gety(q[tail-2]),getx(q[tail-1]),gety(q[tail-1]),getx(i),gety(i))<=0ll)            tail--;            q[tail++]=i;        }        printf("%I64d\n",dp[n]);    }    return 0;}
代码2主要是根据点击打开链接这个链接进行的学习,用图进行结合,很好理解

0 0
原创粉丝点击