【JZOJ 3432】【OnlineJudge 1061】小M的服务器(含斜率优化解释)

Description

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

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

Solution

首先这题的60分方法很简单,只用 fi 表示第i个必选的最小代价;
我们来考虑考虑用斜率优化,
设当前到i,状态j比k要优(j在前),则有:

fj+(ji)(ji1)2<fk+(ki)(ki1)2

移项:
fjfk+j2k2j+k2jk<i

用g(j,k)来表示这个东西,搞一波斜率优化DP即可,
复杂度: O(2n) ;


这里顺便讲一下斜率优化:

斜率优化

斜率优化的g函数是一定满足一个单调性的,前面的一定优于后面的,以本题为例:
设队列中的元素依次为 j1j2,j3,...
有:(这个显然)

i>g(j1,j2)i>g(j2,j3)i>g(j3,j4)...

也有:
i>g(j1,j2)>g(j2,j3)>g(j3,j4)>...

解释如下:假设相邻的3个元素: j1,j2,j3
要想保证以上的式子,就必须当 g(j1,j2)<g(j2,j3) 时,删除 j2
因为:假设 j2 最优,则:
g(j1,j2)>i

g(j2,j3)<i

g(j2,j3)<i<g(j1,j2)

与上面的假设冲突,所以假设不成立,
所以当 g(j1,j2)<g(j2,j3) 时,删除 j2
所以整个式子满足: i>g(j1,j2)>g(j2,j3)>g(j3,j4)>...

Code

#include<cstdio>
#include<cstdlib>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fod(i,a,b) for(LL i=a;i>=b;i--)
using namespace std;
typedef long long LL;
const int N=1000500;
int read(int &n)
{
    char ch=' ';int q=0,w=1;
    for(;(ch!='-')&&((ch<'0')||(ch>'9'));ch=getchar());
    if(ch=='-')w=-1,ch=getchar();
    for(;ch>='0' && ch<='9';ch=getchar())q=q*10+ch-48;n=q*w;return n;
}
int n;
int a[N],S,T;
LL f[N],d[N];
double G(LL i,LL j){return(1.0*(f[i]-f[j]+(i*i-j*j-i+j)/2)/(i-j));} 
int main()
{
    read(n);
    fo(i,1,n) read(a[i]);
    f[n]=a[n];d[S=T=1]=n;
    fod(i,n-1,0)
    {
        while(T>S&&G(d[S],d[S+1])>i)S++;
        f[i]=(d[S]-i)*(d[S]-i-1)/2+f[d[S]]+a[i];
        while(T>S&&G(d[T-1],d[T])<G(d[T],i))T--;
        d[++T]=i;
    }
    printf("%lld\n",f[0]);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值