JZOJ 3432. 【GDOI2014模拟】服务器

Problem

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

这里写图片描述

Solution

向后往前递推

60分方法

设F[i]表示i点直接复制,且右边的所有点已处理完的最小费用。依题意得:

F[i]=min(F[j]+(ji)(ji+1)2)

时间复杂度:O(n^2)

100分算法

方法:斜率优化
如果有两个点j,k,设j比k更优,则有

F[j]+(ji)(ji+1)2+a[i]<F[k]+(ki)(ki+1)2+a[i]

移项,整理,得
2F[j]2F[k]+j2k2j+k)2(jk)<i

我们建立一个队列D,里面的数量关系如下:
d[1]>d[2]>d[3]>….

xl(j,k)=2F[j]2F[k]+j2k2j+k)2(jk)

则我们要把大于i的xl(j,k)统统踢掉,然后将i放入队列。但是一定要保证i暂时是最小的,因此要将队尾的大于i的xl(j,k)统统踢掉。
那么问题来了,为什么要从n-1 downto 0?(看下面的code)因为有的情况是1号服务器不直接复制,且即使1号服务器直接复制,f[1]=f[0],因此用0代表第0号直接复制。因而递推到0,输出f[0].
我讲得不是很好,因为我还是新手,敌不过老司机,希望大家多多包涵。如果想看详细一点的题解,
链接: http://blog.csdn.net/lyd_7_29/article/details/51637686

Code

var a,f,d:array[0..1000001] of int64;
    i,j,l,r,n:longint;
function min(a,b:int64):int64;
begin
    if a<b then exit(a) else exit(b);
end;
function jj(n:int64):int64;
begin
    exit(n*(n+1) div 2);
end;
function xl(j,k:int64):real;
begin
    exit((2*f[j]-2*f[k]+sqr(j)-sqr(k)-j+k)/(2*(j-k)));
end;
begin
    readln(n);
    for i:=1 to n do read(a[i]);
    f[n]:=a[n];
    d[1]:=n;
    l:=1;
    r:=1;
    for i:=n-1 downto 0 do
    begin
        while (l<r)and(i<xl(d[l],d[l+1])) do inc(l);
        f[i]:=f[d[l]]+a[i]+jj(d[l]-i-1);
        while (l<r)and(xl(d[r],i)>xl(d[r-1],d[r])) do dec(r);
        inc(r);
        d[r]:=i;
    end;
    writeln(f[0]);
end.

——2016.6.12

  • 3
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值