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]+(j−i)∗(j−i−1)2+a[i]),j>i
这样做是O(n2)的,TLE。
对于当前的i(i是从后往前枚举的),设有两个决策j,k,j优于k,那么需要满足的条件是
f[j]+(j−i)∗(j−i−1)2+a[i]<f[k]+(k−i)∗(k−i−1)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 long
using 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;
}