您的位置:首页 > Web前端

CSU1963: Feed the rabbit

2017-07-25 11:07 405 查看

CSU1963: Feed the rabbit

Description

There are n holes in a line,the distance between the hole labeled i and i+1 is di。There are also m rabbits, the rabbit labeled i comes to hole ki in time ti. Now you have p people,you can arrange them start at any time(even before time point 0) from the first hole, their speed is 1. They head to hole n without stopping and feed the rabbit on their way without any cost of time. Now you must make every rabbit be fed just one time. You need to minimize the sum of time between arriving and fed for all rabbits.

Input

The first line includes 3 int numbers n,m,p。 The next line includes n-1 numbers,d1,d2,…dn-1。 Next m lines, every line includes 2 numbers, hi and ti, the i th line means that the i th rabbit will arriving at hole hi in time ti.

Output

One number, the minimized sum of waiting time of all rabbits.

Sample Input

4 6 2
1 3 5
1 0
2 1
4 9
1 10
2 10
3 12


Sample Output

3


Hint

30% n,m<=300 100% n,m<=10^5,1<=p<=100,1<=di<=10000,1<=hi<=n,0<=ti<=1090<=ti<=109

Source

2017湖南多校第十三场

Author

alpc

  题目大意就是说有n个坑m只兔子,每只兔子会在ti时间后的hi坑冒头(处于等待状态),有p个人,每个人都可以在任意时间内以1的速度走向n洞并喂食沿途的兔子,求兔子最少的总等待时间

  思路是这样想的:对应每只兔子,都有一个刚好喂到它的人的出发时间(最早),同时实际喂食它的人的出发时间减去这个时间也就是这只兔子等待的时间,同时每个人都一定从1走到n,所以我们就预处理出这个时间。

  以样例为例,处理并排序后的时间为0,0,0,8,9,10,这时问题可以抽象成这样:如何将这样的数组分成至多p段,设每段记为a0,a1,a2,...,an,使得各段对应an∗n−a1−a2−...−an之和最小(an∗n−a1−a2−...−an正好就代表了若一个人喂到了这些兔子,那么这些兔子所需要等待的时间总长,可以想想这是为什么)。

  如0,0,0,8,9,10,将其分为0,0,0和8,9,10两段,前一段的an∗n−a1−a2−...−an为0,后一段为3,这就是最小值了。

  为了方便快速求出分段为(i,j)所对应的值,预处理求数组的前缀和,令sum[n]=∑i=1na[i]

  于是这一段所对应的代价就是a[i]∗(i−j)−(sum[i]−sum[j])。

  比较容易想到这个题要用动态规划,状态转移方程如下:

  f[p][i]=min1≤j≤i{f[p−1][j]+a[i]∗(i−j)−(sum[i]−sum[j])}

  其中p为人数,i为喂食到的兔子的序号(按对应出发时间排)

  花括号内的式子展开为f[p−1][j]+a[i]∗i−a[i]∗j−sum[i]+sum[j],观察发现中间两项仅和i有关,于是变为

  f[p][i]=a[i]∗i−sum[i]+min1≤j≤i{f[p−1][j]−a[i]∗j+sum[j])}

  若已求得j为最优解,那么对于任意的1≤k≤i且k≠j,都有

  f[p−1][j]+sum[j]−a[i]∗j<f[p−1][k]+sum[k]−a[i]∗k

  令yj=f[p−1][j]+sum[j],xj=j,yk=f[p−1][k]+sum[k],xk=k,则有yj−ykxj−xk<a[i]

  首先将会形成上凸的点删去,因为这些点必然不会是最优解的位置,思路与《浅谈数形结合思想在信息学竞赛中的应用》中所说到的是差不多的。

  在之后剩余的点中,我们就需要找到每个i对应的a[i]所对应的最优解,又由上面的式子我们知道对应的最优解就是使得斜率kj,j−1最大但是又不超过a[i],由于这一题我们的a[i]已经排序过了,而留下的点又形成一个下凸的折线,故在计算的时候可以利用单调队列对求解过程进行优化,使得最后的时间复杂度为O(n)。

AC代码

#include <iostream>
#include <queue>
#include <algorithm>
#include <cstring>
#include <string>
#define LL long long
#define ULL unsigned long long
#define mem(a,n) memset(a,n,sizeof(a))
#define fread freopen("in.txt","r",stdin)
#define fwrite freopen("out.txt","w",stdout)
#define N 100100
#define INF 0x3f3f3f3f
#define eps 1e-9
using namespace std;
LL dis
,sum
,dp[110]
,ti
,que
;
inline LL dy(int id,int j,int k){
return dp[id-1][j]+sum[j]-dp[id-1][k]-sum[k];
}
inline LL dx(LL x,LL y){
return x-y;
}
int main()
{
ios::sync_with_stdio(false);
int n,m,p,hole,tim;
while(cin>>n>>m>>p){
dis[1]=0;
for(int i=2;i<=n;++i){
cin>>dis[i];
dis[i]+=dis[i-1];
}
for(int i=1;i<=m;++i){
cin>>hole>>tim;
ti[i]=tim-dis[hole];
}
sort(ti+1,ti+m+1);
for(int i=1;i<=m;++i){
sum[i]=sum[i-1]+ti[i];
}
for(int i=1;i<=m;++i){
dp[1][i]=ti[i]*i-sum[i];
}
for(int i=2;i<=p;++i){
int frt=0,tail=-1;
for(int j=1;j<=m;++j){
while(frt<tail&&dy(i,que[frt+1],que[frt])<
ti[j]*dx(que[frt+1],que[frt])){
++frt;
}
while(frt<tail&&dy(i,que[tail],que[tail-1])*dx(j,que[tail])>=
dy(i,j,que[tail])*dx(que[tail],que[tail-1])){
--tail;
}
que[++tail]=j;
int v=que[frt];
//cout<<dp[i-1][v]<<' '<<sum[v]<<' '<<ti[j]<<' '<<v<<endl;
dp[i][j]=dp[i-1][v]+sum[v]-ti[j]*v+ti[j]*j-sum[j];
//printf("i_%d j_%d %lld\n",i,j,dp[i][j]);
}
}
//for(int i=1;i<=p;i++)
//for(int j=0;j<=m;j++) printf("i_%d j_%d %lld\n",i,j,dp[i][j]);
cout<<dp[p][m]<<endl;
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: