zoukankan      html  css  js  c++  java
  • 题解-Cats Transport

    题解-Cats Transport

    Cats Transport

    (n) 个山丘,(m) 只猫子,(p) 只铲屎官。第 (i-1) 个山丘到第 (i) 个山丘的距离是 (d_i)。第 (i) 只猫子在山丘 (h_i)(t_i) 时间。每个铲屎官可以选择出发时间,然后从 (1) 号山丘一直不停地每秒一个单位走到 (n) 号山丘,领走路上已经玩完的猫。求每只猫都被领走的最小猫子等待时间和。

    数据范围:(2le nle 10^5)(1le mle 10^5)(1le ple 100)(1le d_ile 10^4)(1le h_ile n)(0le t_ile 10^9)


    可以先预处理一下简化问题:

    (D_i=sum_{j=2}^i d_j)

    所以 (1) 号山丘到 (i) 号山丘距离为 (D_i)

    (T_i=t_i-D_{h_i})

    所以可以视为所有猫咪都在 (1) 号山丘,玩完的时间是 (T_i)

    将每只猫咪按 (T_i) 排序,使 (T_{i-1}le T_i)(每只猫子只需要 (T_i) 一个信息即可)。


    所以题目就变成了将序列 (T_i) 分成 (p) 个子序列,使得每个数与它的子序列中最大的数的差的和最小。

    这里的子序列不要求连续,但是很明显在 (T_i) 有序的情况下,连续更优。

    不妨设第 (a) 个铲屎官领走了第 (j+1sim i) 只猫子,即子序列中的最大数为 (T_i),可以如下 ( exttt{dp})

    (f_{a,i}) 表示到第 (a) 个铲屎官领到第 (i) 只猫子的最小等待时间和。

    [f_{a,i}=min{f_{a-1,j}+sum_{h=j+1}^i(T_i-T_h)} ]

    优化一下,令 (s_i=sum_{j=1}^i T_j)

    [egin{split} f_{a,i}=&min{f_{a-1,j}+T_i(i-j)-(s_i-s_j)}\ f_{a,i}=&f_{a-1,j}+T_i(i-j)-(s_i-s_j)\ f_{a,i}=&f_{a-1,j}+iT_i-jT_i-s_i+s_j\ f_{a-1,j}+s_j=&T_icdot j+f_{a,i}+s_i-iT_i\ end{split} \ egin{cases} y=f_{a-1,j}+s_j\ k=T_i\ x=j\ b=f_{a,i}+s_i-iT_i\ end{cases} ]

    套个斜率优化维护 ( exttt{dp}) 最小值下凸壳模板即可。


    时间复杂度 (Theta(n+mlog m+mp)),空间复杂度 (Theta(n+mp))


    Code

    #include <bits/stdc++.h>
    using namespace std;
    
    //Start
    #define re register
    #define il inline
    #define mk make_pair
    #define pb push_back
    #define db double
    #define lng long long
    #define fi first
    #define se second
    const int inf=0x3f3f3f3f;
    const lng INF=0x3f3f3f3f3f3f3f3f;
    
    //Data
    const int N=100000,P=100;
    int n,m,p;
    lng d[N+7],t[N+7],s[N+7];
    
    //DP
    lng f[P+7][N+7];
    pair<int,int> lor[P+7];
    int q[P+7][N+7];
    #define l(x) lor[x].fi
    #define r(x) lor[x].se
    il db X(re int a,re int j){
    	return j;
    }
    il db Y(re int a,re int j){
    	return f[a][j]+s[j];
    }
    il db slope(re int a,re int k,re int t){
    	return (Y(a,k)-Y(a,t))/(X(a,k)-X(a,t));
    }
    il lng F(re int a,re int i,re int j){
    	return f[a-1][j]+t[i]*(i-j)-(s[i]-s[j]);
    }
    il lng DP(){
    	for(re int a=0;a<=p;a++){ //必须初始化
    		lor[a]=mk(1,0);
    		q[a][++r(a)]=0;
    	}
    	for(re int a=1;a<=p;a++){
    		for(re int i=1;i<=m;i++){
    			// printf("(%d,%d)
    ",a,i);
    			while(l(a-1)<r(a-1)&&slope(a-1,q[a-1][l(a-1)],q[a-1][l(a-1)+1])<=t[i]) l(a-1)++;
    			//维护a-1队列递推
    			f[a][i]=F(a,i,q[a-1][l(a-1)]);
    			while(l(a)<r(a)&&slope(a,q[a][r(a)-1],q[a][r(a)])>=slope(a,q[a][r(a)],i)) r(a)--;
    			//维护a队列为递推a+1做准备
    			q[a][++r(a)]=i;
    		}
    	}
    	return f[p][m];
    }
    
    //Main
    int main(){
    	scanf("%d%d%d",&n,&m,&p);
    	if(p>=m) return puts("0"),0;
    	for(re int i=2,x;i<=n;i++){
    		scanf("%d",&x);
    		d[i]=d[i-1]+x;
    	}
    	for(re int i=1,x,y;i<=m;i++){
    		scanf("%d%d",&x,&y);
    		t[i]=-d[x]+y;
    	}
    	sort(t+1,t+m+1);
    	for(re int i=1;i<=m;i++) s[i]=s[i-1]+t[i];
    	printf("%lld
    ",DP());
    	return 0;
    }
    

    祝大家学习愉快!

  • 相关阅读:
    最短路径问题大总结(提纲)
    单源最短路——Bellman-Ford算法
    多源最短路——Floyd算法
    Bracket Sequences Concatenation Problem括号序列拼接问题(栈+map+思维)
    数位DP
    C++ string中的find()函数
    Planning The Expedition(暴力枚举+map迭代器)
    8月5号团队赛补题
    8月3号水题走一波-个人赛五
    Walking Between Houses(贪心+思维)
  • 原文地址:https://www.cnblogs.com/George1123/p/12616203.html
Copyright © 2011-2022 走看看