[題目簡述]
給你一個序列,你要將他們分成連續的若干份.每一份帶給你的收益是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
轉載請註明出處