题意
有N个点,M只兔子,P个饲养员。每只兔子都有一个出现时间,只有在出现时间之后喂食才是有效的。 一个饲养员从任意时间点从起点出发,每分钟走一步,不能停留。要求喂完所有的兔子,问兔子的最小等待时间总和。
题解
这道题非常适合用数形结合的思想去解决,CSU-1963 Feed the rabbit(斜率优化dp)这篇博文讲的非常好,非常新颖而且易懂。
我这里也讲一下自己的理解吧,因为有两个量,时间和距离,首先可以将这个两个量映射到二维空间。很容易便能发现,饲养员所走的路程是一条斜率为1的直线,如果兔子想要被喂食,那么必须要在这条直线的下方出现。这样的话,为了方便处理,我们可以将兔子的点映射到Y轴上。这样的话,一个二维的问题就通过数形结合成功转化为一个一维问题。
我们只需要分配P个点,使得每个兔子点到其上方最近饲养员点的距离最小就可以了。很明显的一个斜率DP的套路。dp[i][j]=dp[i-1][k]+(j-k)*y[j]-(sum[j]-sum[k])。i代表分配了i个饲养员,j代表最后一个饲养员点在j,sum代表前缀和。最后斜率优化一下就可以了。
注意事项
需要注意的是一定要从dp[0][0]开始,其他的dp值都初始化成INF,这样才能保证为了喂了的兔子。
代码
#include <iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<string>
#include<set>
#include<map>
#include<bitset>
#include<stack>
#include<string>
#define UP(i,l,h) for(int i=l;i<h;i++)
#define DOWN(i,h,l) for(int i=h-1;i>=l;i--)
#define W(a) while(a)
#define MEM(a,b) memset(a,b,sizeof(a))
#define LL long long
#define INF 0x3f3f3f3f
#define MAXN 100050
#define MOD 1000000007
#define EPS 1e-3
#define int LL
using namespace std;
int dp[110][MAXN];
int x[MAXN],y[MAXN],sum[MAXN],q[MAXN];
int getUp(int a,int b,int i) {
return dp[i-1][b]-dp[i-1][a]+sum[b]-sum[a];
}
int getDown(int a,int b) {
return b-a;
}
int getDp(int i,int j,int k)
{
return dp[i-1][k]+(j-k)*y[j]-(sum[j]-sum[k]);
}
main() {
// freopen("d://feed5.in","r",stdin);
int n,m,p;
W(~scanf("%lld%lld%lld",&n,&m,&p)) {
MEM(x,0);
MEM(y,0);
MEM(dp,0);
MEM(sum,0);
UP(i,1,n) {
int xx;
scanf("%lld",&xx);
x[i+1]=x[i]+xx;
}
m++;
UP(i,1,m) {
int a,b;
scanf("%lld%lld",&a,&b);
y[i]=(b-x[a]);
}
sort(y+1,y+m);
UP(i,2,m) {
y[i]-=y[1];
sum[i]=y[i]+sum[i-1];
}
MEM(dp,INF);
dp[0][0]=0;
y[1]=0;
UP(i,1,p+1) {
int st=0,ed=0;
q[ed++]=0;
UP(j,1,m) {
// cout<<getUp(q[st],q[st+1],i)<<endl;
W(st+1<ed&&getUp(q[st],q[st+1],i)<=y[j]*getDown(q[st],q[st+1])) {
st++;
}
dp[i][j]=getDp(i,j,q[st]);
// cout<<dp[i][j]<<" "<<i<<" "<<j<<" "<<q[st]<<endl;
W(st+1<ed&&getUp(q[ed-1],j,i)*getDown(q[ed-2],q[ed-1])<=getDown(q[ed-1],j)*getUp(q[ed-2],q[ed-1],i)) {
ed--;
}
q[ed++]=j;
}
}
printf("%lld\n",dp[p][m-1]);
}
}