CF311B Cats Transport

XVII.CF311B Cats Transport

推式子时间到~~~

我们首先对题目中的\(d_i\)做前缀和,求出每座山距离原点距离;

然后对于第\(i\)只猫,如果一个饲养员在\(t_i-d_{h_i}\)时刻以后出发就可以接到它;

注意,饲养员可以在负时刻就出发!!!我之前想多了以为只能在非负时刻出发而纳闷了好半天

我们设\(t_i-d_{h_i}\)为新的\(t_i\),然后将所有的\(t_i\)排序。

然后开始DP:

\(f[i][j]\)表示:前\(i\)只猫,派出\(j\)个人,的最优时间。再设\(s_i\)表示\(t_i\)的前缀和。

则有\(f[i][j]=\min\limits_{k=0}^{i-1}\{f[k][j-1]+t_i*(i-k)-(s_i-s_k)\}\)

我们这样就可以写出\(O(m^2p)\)的代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m,p,d[100100],t[100100],s[100100],f[100100][110],qwq=0x3f3f3f3f3f3f3f3f;
signed main(){
	scanf("%lld%lld%lld",&n,&m,&p),memset(f,0x3f3f3f3f,sizeof(f));
	for(int i=2;i<=n;i++)scanf("%lld",&d[i]),d[i]+=d[i-1];
//	for(int i=1;i<=n;i++)printf("%lld ",d[i]);puts("");
	for(int i=1,x,y;i<=m;i++)scanf("%lld%lld",&x,&y),t[i]=y-d[x];
//	printf("%lld\n",res);
//	for(int i=1;i<=m;i++)printf("%lld ",t[i]);puts("");
	sort(t+1,t+m+1);
	for(int i=1;i<=m;i++)s[i]=s[i-1]+t[i];
//	for(int i=1;i<=m;i++)printf("%lld ",t[i]);puts("");
	f[0][0]=0;
	for(int j=1;j<=p;j++)for(int i=1;i<=m;i++)for(int k=0;k<i;k++)f[i][j]=min(f[i][j],f[k][j-1]+(i-k)*t[i]-(s[i]-s[k]));
	for(int i=1;i<=p;i++)qwq=min(qwq,f[m][i]);
	printf("%lld\n",qwq);
	return 0;
}

然后考虑斜率优化一下:

\(f[i][j]\)中,我们按照列优先(先枚举\(j\))的顺序进行DP;并且,设\(f[i][j-1]\)\(F[i]\)

\(j<k<i\)(不是同一个\(j\))。则如果\(j\)\(k\)优,则有:

\(F_j+t_i*(i-j)-(s_i-s_j)<F_k+t_i*(i-k)-(s_i-s_k)\)

拆开

\(F_j+i*t_i-j*t_i-s_i+s_j<F_k+i*t_i-k*t_i-s_i-s_k\)

抵消

\(F_j-j*t_i+s_j<F_k-k*t_i+s_k\)

移项

\(F_j-F_k+s_j-s_k<(j-k)*t_i\)

除过去(注意\(j-k\)是负数)

\(\dfrac{F_j-F_k+s_j-s_k}{j-k}>t_i\)

右边的\(t_i\)是递增的(排过序了),因此可以采用单调队列维护斜率;然后维护一个下凸壳即可。复杂度\(O(mp)\)

代码:

#include<bits/stdc++.h>
using namespace std;
#define int long long
int n,m,p,d[100100],t[100100],s[100100],f[100100][110],qwq=0x3f3f3f3f3f3f3f3f,l,r,q[100100];
signed main(){
	scanf("%lld%lld%lld",&n,&m,&p),memset(f,0x3f3f3f3f,sizeof(f));
	for(int i=2;i<=n;i++)scanf("%lld",&d[i]),d[i]+=d[i-1];
//	for(int i=1;i<=n;i++)printf("%lld ",d[i]);puts("");
	for(int i=1,x,y;i<=m;i++)scanf("%lld%lld",&x,&y),t[i]=y-d[x];
//	printf("%lld\n",res);
//	for(int i=1;i<=m;i++)printf("%lld ",t[i]);puts("");
	sort(t+1,t+m+1);
	for(int i=1;i<=m;i++)s[i]=s[i-1]+t[i];
//	for(int i=1;i<=m;i++)printf("%lld ",t[i]);puts("");
	f[0][0]=0;
	for(int j=1;j<=p;j++){
		l=r=0;
		for(int i=1;i<=m;i++){
			while(r-l&&(f[q[l]][j-1]-f[q[l+1]][j-1]+s[q[l]]-s[q[l+1]])>=(q[l]-q[l+1])*t[i])l++;
			f[i][j]=f[q[l]][j-1]+(i-q[l])*t[i]-(s[i]-s[q[l]]);
			while(r-l&&(f[q[r-1]][j-1]-f[q[r]][j-1]+s[q[r-1]]-s[q[r]])*(q[r]-i)>=(f[q[r]][j-1]-f[i][j-1]+s[q[r]]-s[i])*(q[r-1]-q[r]))r--;
			q[++r]=i;
		}
	}
	for(int i=1;i<=p;i++)qwq=min(qwq,f[m][i]);
	printf("%lld\n",qwq);
	return 0;
}

原文地址:https://www.cnblogs.com/Troverld/p/14596914.html