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段,设每段记为
如0,0,0,8,9,10,将其分为0,0,0和8,9,10两段,前一段的
为了方便快速求出分段为(i,j)所对应的值,预处理求数组的前缀和,令
于是这一段所对应的代价就是
比较容易想到这个题要用动态规划,状态转移方程如下:
其中p为人数,i为喂食到的兔子的序号(按对应出发时间排)
花括号内的式子展开为
若已求得
令
首先将会形成上凸的点删去,因为这些点必然不会是最优解的位置,思路与《浅谈数形结合思想在信息学竞赛中的应用》中所说到的是差不多的。
在之后剩余的点中,我们就需要找到每个
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[N],sum[N],dp[110][N],ti[N],que[N];
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;
}