摆渡车

题意

你可以操控一辆车的发车时间,你也知道跑一次往返的时间,你还知道每一个人到达车站的时间
让你找到一种方案使得所有人的等待时间之和最少,求这个最小时间

分析

第一反应是把到达车站的人作为一个整体
然后我们可以枚举最近的一次发车时间
假设现在的时间是,最近的一次发车时间是
那么从的等待时间可以表示为
那么我们把这个拆开来看

貌似变得友好了呢
直观感觉一下,我们有效的最近的发车时间应该是不能小于()的
那么其实就是有一部分人在上一次发车时就开始等待了
那么这个也是要加入贡献的

Code

#include <bits/stdc++.h>

using namespace std;

typedef long long ll;
const int maxn = 5e6;

int n, m, t, mt, ans(0x7fffffff);
int cnt[maxn], sum[maxn], f[maxn];

inline int Read()
{
    int x(0);
    char o(getchar());
    while (o < '0' || o > '9') o = getchar();
    for (; o >= '0' && o <= '9'; o = getchar()) x = (x << 1) + (x << 3) + (o ^ 48);
    return x;
}

inline int wait(int l, int r)
{
    return (cnt[r] - cnt[l]) * r - (sum[r] - sum[l]);
}

int main()
{
    n = Read(), m = Read();
    for (int i = 1; i <= n; ++i) {
        mt = max(t = Read(), mt);
        cnt[t]++, sum[t] += t;
    }
    for (int i = 1; i < m + mt; ++i) cnt[i] += cnt[i - 1], sum[i] += sum[i - 1];
    for (int i = 0; i < m + mt; ++i) {
        if (i >= m && cnt[i] == cnt[i - m]) {
            f[i] = f[i - m];
            continue;
        }
        f[i] = cnt[i] * i - sum[i];
        for (int j = max(i - 2 * m + 1, 0); j <= i - m; ++j)
            f[i] = min(f[i], f[j] + wait(j, i));
        if (i >= mt) ans = min(ans, f[i]);
    }
    printf ("%d\n", ans);
}