您的位置:首页 > 其它

bsoj 3733 【模拟试题】打印文章(hdu3507)

2016-04-30 11:12 561 查看
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
);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: