摆渡车
Description
有 n 名同学要乘坐摆渡车从人大附中前往人民大学,第 i 位同学在第 titi分钟去 等车。只有一辆摆渡车在工作,但摆渡车容量可以视为无限大。摆渡车从人大附中出发、 把车上的同学送到人民大学、再回到人大附中(去接其他同学),这样往返一趟总共花费m分钟(同学上下车时间忽略不计)。摆渡车要将所有同学都送到人民大学。
凯凯很好奇,如果他能任意安排摆渡车出发的时间,那么这些同学的等车时间之和最小为多少呢?
注意:摆渡车回到人大附中后可以即刻出发。
Input Format
第一行包含两个正整数 n,m,以一个空格分开,分别代表等车人数和摆渡车往返 一趟的时间。
第二行包含 n 个正整数,相邻两数之间以一个空格分隔,第 i 个非负整数 ti代 表第 i 个同学到达车站的时刻。
Output Format
输出一行,一个整数,表示所有同学等车时间之和的最小值(单位:分钟)。
Sample Input
5 5
11 13 1 5 5
Sample Output
4
————————————————————————————————————————————
斜率优化动态规划
过去没有好好做做这个题,做到斜率优化了才做到,不是那么好做!
首先,需要注意的是最后一次车的出发时间不一定是所有人去等车的时间的最大值。因为可能出现,为了最后等车时间点出发而让好多人等着,这样还不如先送前面的人走,然后再回来接最后的人。
其次,注意用来更新当前时间点的是m分钟之前的时间。所以最近m分钟还不能入队,只能入队m分钟之前的时间。
smg[i]:如果一直没有车来,i时刻等待的人的个数
smt[i]
:如果一直没有车来,i时刻所有人等待的时间之和
所以,f[i]=min(f[j]+smt[i]-smt[j]-smg[j]*(i-j))
然后,设0<j<k<i,且k由于j
所以
f[j]+smt[i]-smt[j]-smg[j]*(i-j)>=
f[k]+smt[i]-smt[k]-smg[k]*(i-k)
在让y(j)=
f[j]+smt[i]-smt[j]+smg[j]*j,x(j)=smg[j]
就有(y(k)-y(j))/(x(k)-x(j))<=i
因为i逐渐增大,所以具有单调性。
注意斜率的处理!!!
————————————————————————————————————————————
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn=4e6+200; 5 ll f[maxn],smt[maxn],smg[maxn]; 6 int t,n,m; 7 int q[maxn],l,r; 8 long long y(int a) 9 { 10 return f[a]-smt[a]+smg[a]*a; 11 } 12 long double get_xl(int j,int k) 13 { 14 return (long double)(y(k)-y(j))/(smg[k]==smg[j]?1e-9:smg[k]-smg[j]); 15 } 16 int main() 17 { 18 // freopen("bus.in","r",stdin); 19 // freopen("bus.out","w",stdout); 20 scanf("%d%d",&n,&m); 21 for(int x,i=1;i<=n;++i) 22 { 23 scanf("%d",&x); 24 t=max(x,t); 25 smg[x]++; 26 } 27 t+=m; 28 for(int i=1;i<=t;++i) 29 { 30 smg[i]+=smg[i-1]; 31 smt[i]=smt[i-1]+smg[i-1]; 32 } 33 l=r=0; 34 for(int i=1;i<=t;++i) 35 { 36 while(l<r&&get_xl(q[l],q[l+1])<=i)++l; 37 if(i<m)f[i]=smt[i]; 38 else if(l<=r)f[i]=min(smt[i],f[q[l]]+smt[i]-smt[q[l]]+smg[q[l]]*q[l]-smg[q[l]]*i); 39 if(i>=m) 40 { 41 while(l<r&&get_xl(q[r-1],q[r])>=get_xl(q[r],i-m+1))r--; 42 q[++r]=i-m+1; 43 } 44 45 } 46 ll ans=0x7fffffffffffffff; 47 for(int i=t-m;i<t;++i)ans=min(ans,f[i]); 48 cout<<ans<<endl; 49 // fclose(stdin);fclose(stdout); 50 return 0; 51 }