题目描述
有n名同学要乘坐校车从阜阳师大东区前往阜阳师大西区,第 i 位同学在第ti 分钟去等车。只有一辆校车在工作,但校车容量可以视为无限大。校车从阜阳师大东区出发、把车上的同学送到阜阳师大西区、再回到阜阳师大东区(去接其他同学),这样往返一趟总共花费 m 分钟(同学上下车时间忽略不计)。校车要将所有同学都送到阜阳师大西区。
乐乐很好奇,如果他能任意安排校车出发的时间,那么这些同学的等车时间之和最小为多少呢?
注意:校车回到阜阳师大东区后可以即刻出发。
输入说明
第一行包含两个正整数n,m,以一个空格分开,分别代表等车人数和校车往返一趟的时间。
第二行包含 n 个正整数,相邻两数之间以一个空格分隔,第 i 个非负整数 ti 代表第 i 个同学到达车站的时刻。
输出说明
输出一行,一个整数,表示所有同学等车时间之和的最小值(单位:分钟)。
输入样例复制
5 1
3 4 4 3 5
输出样例复制
0
数据范围提示
【输入输出样例说明】
同学1和同学4在第3分钟开始等车,等待0分钟,在第3分钟乘坐校车出发。校车在第4分钟回到阜阳师大东区。同学2和同学3在第4分钟开始等车,等待0分钟,在第4分钟乘坐校车出发。校车在第5分钟回到阜阳师大东区。同学5在第5分钟开始等车,等待0分钟,在第5分钟乘坐校车出发。自此所有同学都被送到阜阳师大西区。总等待时间为0。
#include <stdio.h> #include <math.h> using namespace std; const int inf=1<<30; int n, m, t[4000005]; int time, tot[4000005], sum[4000005], f[4000005]; int head, tail, que[4000005], minAns=inf; double slope(int x, int y) { if (tot[x]==tot[y]) return f[y]+sum[y]>f[x]+sum[x] ? 1.0*inf : 1.0*-inf; return (1.0*(f[y]+sum[y])-1.0*(f[x]+sum[x]))/(1.0*(tot[y])-1.0*(tot[x])); } int main() { scanf("%d %d", &n, &m); for (int i=1; i<=n; i++) { scanf("%d", &t[i]); time=fmax(time, t[i]); tot[t[i]]++; sum[t[i]]+=t[i]; } for (int i=1; i<=time+m; i++) { tot[i]+=tot[i-1]; sum[i]+=sum[i-1]; } for (int i=1; i<m; i++) { f[i]=tot[i]*i-sum[i]; } head=tail=1; que[tail]=0; for (int i=m; i<=time+m; i++) { while (head<tail && slope(que[head], que[head+1])<=1.0*i) head++; f[i]=f[que[head]]+(tot[i]-tot[que[head]])*i-(sum[i]-sum[que[head]]); while (head<tail && slope(que[tail-1], que[tail])>=slope(que[tail], i-m+1)) tail--; que[++tail]=i-m+1; if (i>=time) minAns=fmin(minAns, f[i]); } printf("%d", minAns); return 0; }
评判结果