【上海交大OJ1061】小M的服务器

题目源自http://acm.sjtu.edu.cn/OnlineJudge/problem/1061

Description

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

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

Data Constraint

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

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

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

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

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

Solution

对于60%的数据n比较小,我们可以设一个 Fi ,表示当前做到了 i 且第i个采用直接复制的方式,在枚举一个 j(ji) ,表示 i ~j之间的服务器都采用间接复制的方式。
转移显然:

Fi=min(Fj+(ji1)(ji)2)+Ci

然后60%的数据就可以过了。

对于60%+的数据,我们观察上面的式子,如果 Fi Fj 转移过来是最优的,那么 Fi1 就没有必要从 Fj 以后的状态转移过来。

RP得分:70~90

对于100%的数据:
对于每个状态 Fi ,设它可以从 Fj Fk(j>k) 转移过来,那么要满足 Fj<Fk Fi 才可能从 Fj 转移过来。

那么对于 Fj<Fk ,我们有:

Fj+(ji1)(ji)2+Ci<Fk+(ki1)(ki)2+Ci

化简得:

2Fj+j22ijj<2Fk+k22ikk

把含有 i 项的都移到右边,得:

2Fj2Fk+j2jk2+k2(jk)<i

这个式子就满足单调性了。

我们设一个 g(j,k) 表示上方等式左边的结果,一开始把 n 加入队列,用l r 表示队头、队尾。

对于队头的处理,当我们发现g(dl,dl+1)>i时, dl 不比 dl+1 优, l +1

对于队尾的处理,我们要加入一个 i ,当g(dr1,dr)<g(dr,i)时,就可以退队了。

为什么呢?我们分类讨论一下:

i<g(dr1,dr)<g(dr,i) 时, dr dr1 优,但不比 i 优。

g(dr1,dr)<i<g(dr,i)时, dr1 dr 优。

g(dr1,dr)<g(dr,i)<i 时, dr i 优,但不比dr1优。

因此,当 g(dr1,dr)<g(dr,i) 时, dr 都不是最优的,可以退队。

注意一点, Fi 表示 i 必须选,所以答案不是F1,因为 1 <script type="math/tex" id="MathJax-Element-50">1</script>可以不选。

注意乘法。

Code

#include<iostream>
#include<cstdio>
#include<cstdlib>
#define fo(i,j,k) for(int i=j;i<=k;i++)
#define fd(i,j,k) for(int i=j;i>=k;i--)
#define N 1000010
#define ll long long
using namespace std;
ll f[N],a[N];
int d[N];
double g(int i,int j)
{
    return (f[i]*2+i*1ll*i-i-f[j]*2-j*1ll*j+j)*0.5/(i-j);
}
int main()
{
    int n;
    cin>>n;
    fo(i,1,n) scanf("%d",&a[i]);
    f[n]=a[n];
    int l=1,r=1;
    d[1]=n;
    fd(i,n-1,0)
    {
        while(l<r && g(d[l],d[l+1])>i) l++;
        f[i]=f[d[l]]+(d[l]-i)*1ll*(d[l]-i-1)/2+a[i];
        while(l<r && g(d[r-1],d[r])<g(d[r],i)) r--;
        d[++r]=i;
    }
    cout<<f[0];
}
posted @ 2016-06-12 18:44  sadstone  阅读(48)  评论(0编辑  收藏  举报