39 Cat Transport 题解
Cat Transport
题面
小 S 是一个大农场主,他饲养了 \(m\) 只猫,并雇用了 \(p\) 名饲养员。农场中有一条笔直的道路,道路旁有 \(n\) 座山丘,从左到右依次编号为 \(1\) 到 \(n\)。第 \(i\) 座山丘与第 \((i-1)\) 座山丘之间的距离为 \(d_{i}\) 米。所有饲养员都居住在山丘 \(1\)。
某天,猫咪们外出玩耍。第 \(i\) 只猫咪前往山丘 \(h_{i}\),并在时间 \(t_{i}\) 结束游玩,随后在山丘 \(h_{i}\) 等待饲养员接它。
饲养员必须接走所有猫咪。每位饲养员从山丘 \(1\) 走向山丘 \(n\),途中不在任何山丘停留,并带走途中每个山丘上所有等待的猫咪。
饲养员的行走速度为 \(1\) 米/单位时间,且他们的运输能力足够强,可以携带任意数量的猫咪。
例如,假设有两座山丘(\(d_{2}=1\))和一只猫咪,该猫咪在时间 \(3\) 结束游玩于山丘 \(2\)(\(h_{1}=2\))。若饲养员在时间 \(2\) 或时间 \(3\) 离开山丘 \(1\),则能接到这只猫咪;但若在时间 \(1\) 离开则无法接到。若饲养员在时间 \(2\) 出发,猫咪的等待时间为 \(0\);若在时间 \(3\) 出发,猫咪的等待时间为 \(1\)。
你的任务是规划每位饲养员从山丘 \(1\) 出发的时间,使得所有猫咪的等待时间总和最小。
\(2 \le n \le 10^5,\ 1 \le m \le 10^5,\ 1 \le p \le 100, 1 \le d_{i} < 10^4,1 \le h_i \le n,\ 0 \le t_i \le 10^9\)。
题解
模拟一下发现这道题的山好像没什么用,只有距离是有用的
我们设 \(A_i\) 表示如果在 \(A_i\) 时刻出发,刚好能够带走猫 \(i\) ,那么 \(A_i = T_i - \sum d_j\)
设出发时刻为 \(t\) ,那么这个饲养员能够接到猫 \(i\) 当且仅当 \(A_i \le t\) ,等待时间为 \(t - A_i\)
如果我们按照 \(A_i\) 将猫排序,那么每次被带走的猫就是连续的一段,更方便我们dp
所以设 \(f(i,j)\) 表示前 \(i\) 个饲养员带走前 \(j\) 个猫的最小等待时间,设 \(s\) 为 \(A\) 的前缀和数组
假设第 \(i\) 个饲养员要带走 \(k + 1 \sim j\) 这一段的猫,那么他最早要在 \(A_j\) 时刻出发,这一段猫的最小等待时间为
转移方程
这个方程暴力转移是 \(O(pm^2)\) 的,考虑优化,发现其中有 \(A_j \times k\) 项,所以不能用单调队列直接写
考虑斜率优化,去掉 \(\min\) 将方程变形
发现直线的斜率 \(A_j\) 单调增,决策点 \(x\) 坐标 \(k\) 单调增,所以直接普通的斜率优化(任务安排 2)
时间复杂度为 \(O(pm)\)
code
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
typedef long long ll;
const int N = 1e5 + 10;
int n, m, p;
int q[N];
ll sd[N], a[N], s[N], f[110][N];
double slope (int i, int p, int q) {
return (double)(f[i - 1][q] + s[q] - f[i - 1][p] - s[p]) / (q - p);
}
int main () {
cin >> n >> m >> p;
for (int i = 2; i <= n; i ++) {
scanf ("%lld", &sd[i]);
sd[i] += sd[i - 1];
}
for (int i = 1; i <= m; i ++) {
int pos, ed;
scanf ("%d%d", &pos, &ed);
a[i] = ed - sd[pos];
}
sort (a + 1, a + 1 + m);
for (int i = 1; i <= m; i ++) {
s[i] = s[i - 1] + a[i];
}
//注意初始化
memset (f, 0x3f, sizeof f);
f[0][0] = 0;
for (int i = 1; i <= p; i ++) {
int h = 1, t = 0;
for (int j = 1; j <= m; j ++) {
while (h < t && slope (i, q[t - 1], q[t]) >= slope (i, q[t], j - 1)) t --;
q[ ++ t] = j - 1;
while (h < t && slope (i, q[h], q[h + 1]) <= a[j]) h ++;
int k = q[h];
f[i][j] = f[i - 1][k] + a[j] * (j - k) - s[j] + s[k];
}
}
cout << f[p][m] << endl;
return 0;
}

浙公网安备 33010602011771号