Description
給出N個單詞,每個單詞有個非負權值Ci,現要將它們分成連續的若干段,每段的代價爲此段單詞的權值和,還要加一個常數M,即(∑Ci)^2+M。現在想求出一種最優方案,使得總費用之和最小。
Input
包含多組測試數據,對於每組測試數據。第一行包含兩個整數N和M(0 <= N <= 500000,0 <= M <= 1000),第二行爲N個整數。
Output
輸出僅一個整數,表示最小的價值。
Sample Input
5 5
5 9 5 7 5
Sample Output
230
剛學了斜率優化:
F[i]=min(F[j]+(S[i]-S[j])^2)+M;
設j
G[j]=F[j]+(S[i]-S[j])^2;
假設 G[j]>G[k]
F[j]+(S[i]-S[j])^2>F[k]+(S[i]-S[k])^2
(S[i]-S[j])^2=S[i]^2-2*S[i]*S[j]+S[j]^2
F[j]-F[k]+S[j]^2-S[k]^2>2*S[i]*(S[j]-S[k])
∵S[k]>S[j]
∴(F[j]-F[k]+S[j]^2-S[k]^2)/(S[j]-S[k])<2*S[i];
令Slope[j][k]=(F[j]-F[k]+S[j]^2-S[k]^2)/(S[j]-S[k]);
當Slope[j][k]<2*S[i]時,k比j優
初略算了一下。
好像還行吧.
#include<iostream>
#include<iomanip>
#include<cstring>
#include<cmath>
#include<cstdio>
using namespace std;
long long S[500005];
long long f[500005];
int q[500005];
double Slope(int j,int k){
return (f[j]-f[k]+S[j]*S[j]-S[k]*S[k])*1.0/(S[j]-S[k]);
}
int main(){
int n;
int M;
while(scanf("%d",&n)==1){
scanf("%d",&M);
int x;
for(int i=1;i<=n;i++){
scanf("%d",&x);
S[i]=S[i-1]+x;
}
int l=1;int r=1;
f[0]=0;q[1]=0;
for(int i=1;i<=n;i++){
while(l<r&&Slope(q[l],q[l+1])<2*S[i])l++;
int j=q[l];
f[i]=f[j]+(S[i]-S[j])*(S[i]-S[j])+M;
while(l<r&&Slope(q[r-1],q[r])>Slope(q[r],i))r--;
q[++r]=i;
}
printf("%lld\n",f[n]);
}
return 0;
}