3432. 【GDOI2014模拟】服务器

来源:互联网 发布:淘宝达人等级v2怎么升 编辑:程序博客网 时间:2024/06/05 20:29

Description

我们需要将一个文件复制到n个服务器上,这些服务器的编号为S1, S2, …, Sn。

首先,我们可以选择一些服务器,直接把文件复制到它们中;将文件复制到服务器Si上,需要花费ci > 0的置放费用。对于没有直接被复制文件的服务器Si来说,它依次向后检查Si+1, Si+2, …直到找到一台服务器Sj:Sj中的文件是通过直接复制得到的,于是Si从Sj处间接复制得到该文件,这种复制方式的读取费用是j – i(注意j>i)。另外,Sn中的文件必须是通过直接复制得到的,因为它不可能间接的通过别的服务器进行复制。我们设计一种复制方案,即对每一台服务器确定它是通过直接还是间接的方式进行复制(Sn只能通过直接方式),最终使每一台服务器都得到文件,且总花费最小。

Input

输入文件的第一行有一个整数n,表示服务器的数目。输入文件的第二行有n个整数,顺数第i个表示ci:在Si上直接复制文件的费用。

Output

输出文件中只包含一个整数,即最少需要花费的费用。

Sample Input

10

2 3 1 5 4 5 6 3 1 2

Sample Output

18

Data Constraint

60%的数据中,1 <= n <= 1 000

100%的数据中,1 <= n <= 1 000 000

80%的数据中, 1 <= ci <= 50

100%的数据中,1 <= ci <= 1 000 000 000

最终结果可能较大,请注意选择适当的数据类型进行计算。

Hint

这里写图片描述

题解(转载LYD729)f[i]=min(f[j]+(ji)∗(ji1)2+a[i]),j>i 这样做是O(n2)的,TLE。 对于当前的ii是从后往前枚举的),设有两个决策j,k,j优于k,那么需要满足的条件是 f[j]+(ji)∗(ji1)2+a[i]<f[k]+(k−i)∗(k−i1)2+a[i]移项,整理得 f[j]−f[k]+j2−k2−j+k2j−k<i设g(j,k)表示不等式左边。 所以我们维护一个单调递减的队列,里面大概长成这个样子 i>g(jl,jl+1)>g(jl+1,jl+2)>⋯>g(jr−1,jr)队头即jl为对于当前的i的最优解。 然后我们i是递减的,所以一旦有i<g(jl,jl+1)则令jl出队,因为这说明jl不再是最优的了。 而做完当前的i之后,也要将其加入队列。 若有g(jr−1,jr)<g(jr,i)则说明jr永远不可能取到最优了,证明如下: 采用反证法,假设jr能够取到最优,则 jr优于jr−1等价于g(jr−1,jr)>i, jr优于i等价于g(jr,i)<i。 综合上面两个不等式,得 g(jr,i)<i<g(jr−1,jr)。 惊奇地发现不等式出现了矛盾! 得证! 所以要把jr踢掉,一直做下去直到不满足上述条件,然后让i入队。 但是,naive的我曾经有过这样一个疑问,为什么不能直接用g(i,jr)即i优于jr来判断队尾的出队情况呢? 因为当前i优于jr并不代表以后的i亦优于jr(这个证明是感性的,凑合理解吧)。 
#include<cstdio>#define N 1000005#define ll long longusing namespace std;int n;ll a[N],f[N],q[N];double g(ll j,ll k){    return (f[j]-f[k]+(j*j-k*k-j+k)/2.0)/(j-k);}int main(){    scanf("%d",&n);    for(int i=1;i<=n;i++)        scanf("%lld",&a[i]);        f[n]=a[n];    int h=1,t=1;    q[1]=n;    for(int i=n-1;i>=0;i--)    {        while(h<t&&i<g(q[h],q[h+1])) h++;        int j=q[h];        f[i]=f[j]+a[i]+(j-i)*(j-i-1)/2;        while(h<t&&g(q[t-1],q[t])<g(i,q[t])) t--;        q[++t]=i;    }    printf("%lld",f[0]);    return 0;}