【题意】
1、第i个同学在第t[i]分钟到达车站
2、摆渡车一次可以装下无数人
3、两次发车的间隔时间m分钟
求所有等车时间和的最小值
【解题】
我们不妨认为时间是一条数轴,每名同学按照到达时刻分别对应数轴上可能重合的点。
安排车辆的工作,等同于将数轴分成若干个左开右闭段,每段的长度⩾m。原本的等车时间之和,自然就转换成所有点到各自所属段右边界的距离之和。
.
令f(i)表示在第i分钟发出一班车时,所需要等待的最小时间。最后一个人到车站的时间为t
则有: f(i)=min{f(k)+∑(i-a[j],k<a[j]<=i)} 其中 0<=k<=i-m
其最终答案:ans=min{f(i)} 其中t<=i<t+m
这个DP方程的复杂度为O(t2n)
1、前缀和优化
对于∑(i-a[j],k<a[j]<=i)
令cnt[i]表示从0到i时间为止到达车站的人数和
令sum[i]表示从0到i时间为止到达车站的人的时间总和
则有∑(i-a[j],k<a[j]<=i) =i*(cnt[i]-cnt[k])-(sum[i]-sum[k])
即DP方程为 f(i)=min{f(k)+i*(cnt[i]-cnt[k]) -(sum[i]-sum[k])} 其中k<=i-m
此时,时间复杂度降为O(t2)
2、转移优化
试想一下,没有一个同学会等待超过2m分钟。
因为最坏情况下,在k时刻发出了一辆车,有位同学在k+1时刻到达了车站,摆渡车将会在k+m时刻返回,考虑到等待其他学生的情况,摆渡车最晚会在k+2m-1时刻发出(不然还不如在k+m时刻和k+2m时刻各发出一辆)
此时,DP方程为: f(i)=min{f(k)+i*(cnt[i]-cnt[k]) -(sum[i]-sum[k])} 其中i-2m<k<=i-m
此时,时间复杂度为O(tm)
3、状态压缩
很显然,根据上一条优化的结论,当顺序相邻的两位同学的时间间隔超过2m的时候,其中的状态都是无用的,可以直接压缩至2m
即对a排序后,若a[i+1]-a[i]>2m, 则对后续所有的a[k,k>i]-=a[i+1]-a[i]-2m
另外,可以将DP的起点定为第一个同学到达的时间 则最后到车站的时间t最大为2m*n
此时,时间复杂度为O(tm)=O(m2n) 解决
【代码】
1 #include <bits/stdc++.h> 2 using namespace std; 3 const int N = 500 +5; 4 const int M = 100 +5; 5 const int T = 4000000 +5; 6 typedef long long ll; 7 ll n,m,t; 8 l