bsoj 3733 【模擬試題】打印文章(hdu3507)

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< k
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;
}

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章