[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

轉載請註明出處

發佈了45 篇原創文章 · 獲贊 5 · 訪問量 6萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章