[apio2010]特别行动队(斜率优化的dp)

[题目简述]

        给你一个序列,你要将他们分成连续的若干份.每一份带给你的收益是ax^2+bx+c,其中x是这一份的和,a<0

[题解]

        对于这道题,我们可以很容易的写出方程:f[i]=max(f[j]+a*(s[i]-s[j])^2+b*(s[i]-s[j])+c);因为数据范围是100W,所以我们猜测这个dp要用斜率优化或单调队列优化.

        现在我们对他做一下变形.

        f[i]=max(f[j]+a*(s[i]*s[i]+s[j]*s[j]+2*s[i]*s[j])+b*(s[i]-s[j])+c)
            =max(f[j]+a*a[j]*a[j]+2*a*s[i]*s[j]-b*s[j])+a*s[i]*s[i]+b*s[i]+c

        可以发现,f[j]+a*a[j]*a[j]-b*s[j]只与j有关,a*s[i]*s[i]+b*s[i]+c只与i有关,2*a*s[i]*s[j]与i,j有关且单调递减(a<0),而f[j]+a*a[j]*a[j]-b*s[j]则没有单调性.

        我们令k=a*s[i]*s[i]+b*s[i]+c,x[i]=2*a*s[i],y[i]=f[i]+a*a[i]*a[i]-b*s[i],则:f[i]=max(y[i]+s[i]*x[i])+k

        令P=y[j]+s[i]*x[j],我们的目标就是最大化P.移项得:y[j]=P-s[i]*x[j].

       我们再令x[j]=-x[j],则:y[j]=s[i]*x[j]+P.其中,x随j单调递增.由于s随i单调递增,所以直线的斜率也单调递增,所以我们可以利用斜率优化来解决这道题.

Code:

program commando;
type int=longint;real=extended;
var
        i,j,m,l,r,n:int;
        a,b,k,c:real;
        x,y,f,s:array[0..1000000]of real;
        q:array[0..1000000]of int;

begin
        assign(input,'commando.in');reset(input);
        assign(output,'commando.out');rewrite(output);
        read(n);
        read(a,b,c);s[0]:=0;
        for i:=1 to n do begin
                read(s[i]);s[i]:=s[i-1]+s[i];
        end;
        l:=1;r:=1;q[l]:=0;f[0]:=0;
        for i:=1 to n do begin
                k:=c+b*s[i]+a*s[i]*s[i];
                while(l<r)and((y[q[l]]-y[q[l+1]])/(x[q[l]]-x[q[l+1]])<s[i])do inc(l);
                f[i]:=k+y[q[l]]-s[i]*x[q[l]];
                x[i]:=2*a*s[i];y[i]:=f[i]-b*s[i]+a*s[i]*s[i];
                while(l<r)and((y[q[r]]-y[q[r-1]])/(x[q[r]]-x[q[r-1]])>(y[q[r]]-y[i])/(x[q[r]]-x[i]))do dec(r);
                inc(r);q[r]:=i;
        end;
        write(f[n]:0:0);
        close(input);close(output);
end.

另外,我想申明一下,由于本人写blog的主要目的是将刚学过的东西巩固一下,所以代码的效率不一定有多高,实现方式不一定很精简,请某些同学就不要挑一些小毛病了.贴上来的程序只是做一个参考,不过我还是会保证正确性的.


BY QW

转载请注明出处

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值