[hdu3507] 打印文章

来源:互联网 发布:中广电网络机顶盒好嘛 编辑:程序博客网 时间:2024/06/02 06:47

题目描述

给出N个单词,每个单词有个非负权值Ci,现要将它们分成连续的若干段,每段的代价为此段单词的权值和,还要加一个常数M,即(∑Ci)^2+M。现在想求出一种最优方案,使得总费用之和最小。


输入格式

包含多组测试数据,对于每组测试数据。第一行包含两个整数N和M(0 <= N <= 500000,0 <= M <= 1000),第二行为N个整数。


输出格式

输出仅一个整数,表示最小的价值。


样例数据

样例输入

5 5
5 9 5 7 5

样例输出

230


题目分析

见斜率优化总结的引例


源代码

#include<algorithm>#include<iostream>#include<iomanip>#include<cstring>#include<cstdlib>#include<vector>#include<cstdio>#include<cmath>#include<queue>using namespace std;inline const int Get_Int() {    int num=0,bj=1;    char x=getchar();    while(x<'0'||x>'9') {        if(x=='-')bj=-1;        x=getchar();    }    while(x>='0'&&x<='9') {        num=num*10+x-'0';        x=getchar();    }    return num*bj;}long long n,m,Q[500005],f[500005],s[500005];double Slope(long long j,long long k) { //求斜率     return double((f[j]+s[j]*s[j])-(f[k]+s[k]*s[k]))/(2*s[j]-2*s[k]);}int main() {    while(scanf("%lld%lld",&n,&m)!=EOF) {        for(int i=1; i<=n; i++)s[i]=s[i-1]+Get_Int();        int Left=1,Right=1;        Q[1]=0;        f[0]=0;        for(int i=1; i<=n; i++) {            while(Left<Right&&Slope(Q[Left],Q[Left+1])<=s[i])Left++; //维护队首(删除非最优决策)             int Front=Q[Left];            f[i]=f[Front]+(s[i]-s[Front])*(s[i]-s[Front])+m; //计算当前f             while(Left<Right&&Slope(Q[Right-1],Q[Right])>=Slope(Q[Right],i))Right--; //维护队尾(维护下凸包性质)             Q[++Right]=i; //入队         }        printf("%lld\n",f[n]);    }    return 0;}

0 0
原创粉丝点击