一些山距离起点有距离且不同,m只猫要到不同的山上去玩ti时间,有p个铲屎官人要去把所有猫接走,步行速度为1单位每秒,从1走到N座山不停下,必须在猫玩完后才可以把他带走。可以提前出发。问所有猫最少等待时间之和。
这题一开始有个模糊想法就是$f[i][j]$表示前i个人接j只猫,但是猫是乱序的,必须找一种方法顺序的dp。想到排序。但是排时间抑或是距离都不对,要考虑优先接哪个。然后瞎想到每只猫可以让人在$T_i-dis_i$时刻从起点出发正好接到不用等,那接一堆猫等待时间取决于要求出发最迟的那只猫。把每只猫正好接到要求的出发时间做一下从小到大排个序,一个人接某批猫,每只猫的等待时间就是最大出发时间减去接这只猫的出发时间。然后考虑在这上面dp。然而选的猫不一定连续。可以证明(怎么证?我也不会),只有每个人接这里面连续的一批猫才有可能产生最优解。可以意会一下,我原来连续的一段,中间有一个给下一个人带走,等待时间更长,给上一个人带走,差不多、大概、应当也不优。实在不行可以打表看一下,比较其他划分有没有比连续划分优的。反正我是根据类似经历感觉出来的。
然后方程很好写,区间划分。sum是等待时间前缀和,方便转移。a是等待时间,注意在排完序后就单调了。
$f[i][j]=min\{f[i-1][k]+(j-k)*a[j]-(sum[j]-sum[k])\} $ $ i<=j<=n $ $ i-1<=k<j$
然后拆开写斜截式,搞搞就斜率优化维护下凸壳,又斜率单调增,所以上述$O(pm^2)$化为$O(pm)$
$f[i-1][k]+sum[k]=a[j]*k+j*a[j]+f[i][j]+sum[j]$
记下错误:
初始化又错!初始化又错!初始化又错!LINE23.真的不能再犯了。。。
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 template<typename T>inline char MIN(T&A,T B){return A>B?A=B,1:0;} 5 template<typename T>inline char MAX(T&A,T B){return A<B?A=B,1:0;} 6 template<typename T>inline T _min(T A,T B){return A<B?A:B;} 7 template<typename T>inline T _max(T A,T B){return A>B?A:B;} 8 template<typename T>inline T read(T&x){ 9 x=0;int f=0;char c;while(!isdigit(c=getchar()))if(c=='-')f=1; 10 while(isdigit(c))x=x*10+c-'0',c=getchar();return f?x=-x:x; 11 } 12 const int N=100000+7; 13 ll f[103][N],d[N],a[N],sum[N],hi,ti; 14 int q[N]; 15 int n,m,p,l,r; 16 inline ll y(int k,int i){return f[i-1][k]+sum[k];} 17 18 int main(){//freopen("test.in","r",stdin);//freopen("tmp.out","w",stdout); 19 read(n),read(m),read(p);if(p>=m)return printf("0\n"),0; 20 for(register int i=2;i<=n;++i)d[i]=read(d[i])+d[i-1]; 21 for(register int i=1;i<=m;++i)read(hi),read(ti),a[i]=ti-d[hi]; 22 sort(a+1,a+m+1); 23 for(register int i=1;i<=m;++i)sum[i]=a[i]+sum[i-1],f[1][i]=i*1ll*a[i]-sum[i];//MISTAKES! 24 for(register int i=2;i<=p;++i){ 25 q[l=r=1]=i-1; 26 for(register int j=i;j<=m;++j){ 27 while(l<r&&y(q[l+1],i)-y(q[l],i)<=(q[l+1]-q[l])*1ll*a[j])++l; 28 f[i][j]=f[i-1][q[l]]+(j-q[l])*1ll*a[j]-sum[j]+sum[q[l]]; 29 while(l<r&&(y(q[r],i)-y(q[r-1],i))*(j-q[r])>=(y(j,i)-y(q[r],i))*(q[r]-q[r-1]))--r; 30 q[++r]=j; 31 } 32 } 33 printf("%I64d\n",f[p][m]); 34 return 0; 35 }