【GDOI2014模拟】服务器
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
反思&题解
比赛思路: 只是粗略地看了看题,其他时间都一直在干T1和T2
正解思路: 设
表示这个服务器直接复制的最小话费,那么很显然第n个服务器是必须直接复制的,因为它无法从另外的服务器间接复制,所以
,因为是从最后一个服务器开始转移的,所以需要倒着处理,之后考虑转移,思考一下,不难推出转移方程为:
之后可以看到这个转移是
的,过不了,不过我们可以发现
这一段是只包含j的,所以我们直接用单调队列维护一下就OK了。(这题还可以用斜率优化做,但是我还没学,就用了单调队列)
反思: 时间分配要注意,还有善用学过的知识(话说单调队列我差不多有半年没打了)
CODE
#include<bits/stdc++.h>
using namespace std;
long long n,c[1000005],f[1000005],d[1000005][2],ans;
int main()
{
scanf("%lld",&n);
long long i;
for (i=1;i<=n;i++)
scanf("%lld",&c[i]);
f[n]=n*(n-1)/2+c[n];
long long head=1,tail=1;
d[1][0]=c[n];
d[1][1]=n;
ans=f[n];
for (i=n-1;i>=1;i--)
{
long long j,mn=1e15,mnnum;
for (j=head;j<=tail;j++)
{
if (d[j][0]+(d[j][1]-i)*(d[j][1]-i-1)/2<=mn)
{
mnnum=j;
mn=d[j][0]+(d[j][1]-i)*(d[j][1]-i-1)/2;
}
}
head=mnnum;
f[i]=d[head][0]+(d[head][1]-i)*(d[head][1]-i-1)/2+c[i]+i*(i-1)/2;
ans=min(ans,f[i]);
while (head<=tail && d[tail][0]>f[i]-i*(i-1)/2) tail--;
d[++tail][0]=f[i]-i*(i-1)/2;
d[tail][1]=i;
}
printf("%lld\n",ans);
return 0;
}