题目信息
解题思路
法1:三维dp
dpijk:轮到第i个人的后j秒时间,一班车有k个人。
- 第n个人一定是在tn到tn+m-1这段时间被接走的
- 转移方程:
定义di为第i个人个第i+1个人的时间差。
①考虑j的时间之外是否值得多花时间:
dp[i][j][k] = dp[i + 1][j - d[i]][k + 1] + k * d[i](当j > di时)
②转移时间已有j,考虑多等一个人上车的两种情况:
dp[i][j][k] = min(dp[i + 1][0][k + 1] + k * gap[i], dp[i + 1][max(0, j - d[i]) + m][1] + k * j)(当j > di时)
法2:一维dp
- 我们可以认为时间是一条数轴,每名同学按照到达时间在数轴上排列。安排车辆将数轴分段,每段长度≥m。原来的等车时间和,就变成了所有点到个子段右边界的距离。
- 状态转移方程:
定义a为前缀和数组。
dp[i] = min j ≤ i - m(dp[j] + (a[i] - a[j]) * i - sum[i] + sum[j]) - 优化:前缀和。
特别提醒: 未吸氧的话只能得70pts,后面会TLE。
代码实现
法1
#include <bits/stdc++.h>
using namespace std;
const int N = 4000005;
int a[N], s[N], dp[N];
int main() {
ios :: sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int n, m, t = 0;
cin >> n >> m;
for (int i = 1; i <= n; ++i) {
int x;
cin >> x;
++a[x];
s[x] += x;
t = max(t, x);
}
for (int i = 1; i < t + m; ++i) {
a[i] += a[i - 1];
s[i] += s[i - 1];
}
for (int i = 1; i < t + m; ++i) {
dp[i] = a[i] * i - s[i];
for (int j = max(i - 2 * m + 1, 0); j <= i - m; ++j) {
dp[i] = min(dp[i], dp[j] + (a[i] - a[j]) * i - (s[i] - s[j]));
}
}
int res = INT_MAX;
for (int i = t; i < t + m; ++i) {
res = min(res, dp[i]);
}
cout << res << '\n';
return 0;
}