【洛谷 P5017】 擺渡車(斜率優化)

題目鏈接
算是鞏固了一下斜率優化吧。
\(f[i]\)表示前\(i\)分鐘最少等待時間。
則有\(f[i]=\min_{j=0}^{i-m}f[j]+(cnt[i]-cnt[j])*i-(sum[i]-sum[j])\)
其中\(cnt[i]\)\(sum[i]\)分別表示前\(i\)分鐘去等車的學生數量和他們去等車的時刻之和。
變形一下得\(f[j]+sum[j]=i*cnt[j]+i*cnt[i]-sum[i]-f[i]\)
維護一個下凸包即可。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAXN = 510;
const int MAXT = 4000010;
int n, m, t[MAXN], cnt[MAXT], sum[MAXT], f[MAXT], ans = 2147483647, q[MAXT], head, tail;
inline double k(int i, int j){
    return (double)(f[j] + sum[j] - f[i] - sum[i]) / (cnt[i] == cnt[j] ? 1e-9 : cnt[j] - cnt[i]);
}
int main(){
    scanf("%d%d", &n, &m);
    for(int i = 1; i <= n; ++i){
        scanf("%d", &t[i]);
        cnt[t[i]]++;
        sum[t[i]] += t[i]; 
    }
    sort(t + 1, t + n + 1);
    for(int i = 0; i < t[n] + m; ++i)
        cnt[i] += cnt[i - 1], sum[i] += sum[i - 1];
    for(int i = 0; i < m; ++i)
        f[i] = cnt[i] * i - sum[i];
    for(int i = m; i < t[n] + m; ++i){
        while(head < tail && k(q[tail - 1], q[tail]) >= k(q[tail], i - m)) --tail;
        q[++tail] = i - m;
        while(head < tail && k(q[head], q[head + 1]) <= i) ++head;
        int j = q[head];
        f[i] = f[j] + (cnt[i] - cnt[j]) * i - (sum[i] - sum[j]);
        if(i >= t[n]) ans = min(ans, f[i]);
    }
    printf("%d\n", ans);
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章