【GDOI2014模拟】JZOJ2020年8月14日提高组 服务器

时间:2023-03-10 04:29:56
【GDOI2014模拟】JZOJ2020年8月14日提高组 服务器

【GDOI2014模拟】JZOJ2020年8月14日提高组 服务器

题目

Time and Memory Limits

【GDOI2014模拟】JZOJ2020年8月14日提高组 服务器

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

【GDOI2014模拟】JZOJ2020年8月14日提高组 服务器

题解

题意

给出\(n\)个点

每个点可以选择两种操作

一种是直接复制,费用为\(a_i\)

一种是间接复制,费用为\(i\)后面第一个直接复制的\(j\)的\(j-i\)

\(n\)号点必须直接复制

问最小代价

分析

考虑\(DP\)

设\(f[i]\)表示\(i\)点直接复制和间接复制的总和

那么转移

\(f[i]=min\{f[j]+j*(j-i)-\dfrac{(j-i)(j+i-1)}{2}\}\)

转移\(n^2\),过不了

思考优化

发现可以斜率优化

优化

\(\dfrac{f[j]-f[k]+\dfrac{j^2-k^2+k-j}{2}}{j-k}<i(j>k)\)

单调队列维护

Code

#include<bits/stdc++.h>
using namespace std;
long long n,l,r,ans,f[1000005],q[1000005],a[1000005];
long long read()
{
long long res=0;char ch;
ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
while (ch>='0'&&ch<='9')
{
res=(res<<1)+(res<<3)+(ch-'0');
ch=getchar();
}
return res;
}
long long get(long long l,long long r)
{
return r*(r-l)-(r+l-1)*(r-l)/2;
}
double slope(long long x,long long y)
{
return (f[x]-f[y]+(x*x-y*y+y-x)/2)*1.0/(x-y);
}
int main()
{
n=read();
for (long long i=1;i<=n;i++)
a[i]=read();
f[n]=a[n];
l=1;
r=1;
q[1]=n;
for (long long i=n-1;i;i--)
{
while (l<r&&slope(q[l],q[l+1])>=i) l++;
f[i]=a[i]+f[q[l]]+get(i+1,q[l]);
while (l<r&&slope(q[r-1],q[r])<slope(q[r],i)) r--;
q[++r]=i;
}
ans=99999999999999;
for (long long i=1;i<=n;i++)
ans=min(ans,f[i]+get(1,i));
printf("%lld\n",ans);
return 0;
}