NOIP2018PJ「摆渡车」

Description

有 n 名同学要乘坐摆渡车从人大附中前往人民大学,第 i 位同学在第 ti 分钟去等车。只有一辆摆渡车在工作,但摆渡车容量可以视为无限大。摆渡车从人大附中出发、把车上的同学送到人民大学、再回到人大附中(去接其他同学),这样往返一趟总共花费 m 分钟(同学上下车时间忽略不计)。摆渡车要将所有同学都送到人民大学。
凯凯很好奇,如果他能任意安排摆渡车出发的时间,那么这些同学的等车时间之和最小为多少呢?
注意:摆渡车回到人大附中后可以即刻出发。

啊…是久违的摆渡车。
现在兴致一来准备用斜率优化水一发。

待完善。

/*
f[i]=min(f[i], f[j]+(tot[i]-tot[j])*i-(sum[i]-sum[j]));
f[i]=min(f[i], f[j]+tot[i]*i-tot[j]*i-sum[i]+sum[j]);
f[i]=(tot[i]*i-sum[i])+min((f[j]+sum[j])-tot[j]*i);
f[i]=f[j]+sum[j]-tot[j]*i+tot[i]*i-sum[i];
f[j]+sum[j]=tot[j]*i+f[i]-tot[i]*i+sum[i];
*/
#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;
}
posted @ 2020-08-14 22:36  willbe233  阅读(156)  评论(0)    收藏  举报