Blog of RuSun

\begin {array}{c} \mathfrak {One Problem Is Difficult} \\\\ \mathfrak {Because You Don't Know} \\\\ \mathfrak {Why It Is Diffucult} \end {array}

CF311B Cats Transport

LuoGu: CF311B Cats Transport

CF: B. Cats Transport

先计算出什么时候出发可以刚好接到每个猫。显然,一段连续的由一个人接是最优的。

于是问题转化为经典的序列分割的问题。可以用斜率优化。

查看代码
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
#include <cstdio>
#include <algorithm>
using namespace std;
typedef long long LL;
const LL inf = 1e18;
const int N = 1e5 + 10;
int hd, tl, q[N];
int n, m, p;
LL d[N], t[N], s[N], f[2][N];
double slp(int u, int a, int b)
{
return (double)(f[u & 1][a] + s[a] - f[u & 1][b] - s[b]) / (double)(a - b);
}
int main()
{
scanf("%d%d%d", &n, &m, &p);
for (int i = 2; i <= n; i++)
scanf("%d", &d[i]);
for (int i = 2; i <= n; i++)
d[i] += d[i - 1];
for (int i = 1, h; i <= m; i++)
{
scanf("%d%d", &h, &t[i]);
t[i] -= d[h];
}
sort(t + 1, t + m + 1);
for (int i = 1; i <= m; i++)
s[i] = s[i - 1] + t[i];
for (int i = 1; i <= m; i++)
f[1][i] = t[i] * i - s[i];
for (int i = 2; i <= p; i++)
{
hd = 1, tl = 0;
q[++tl] = 0;
for (int j = 1; j <= m; j++)
{
f[i & 1][j] = inf;
while (hd < tl && slp(i - 1, q[hd], q[hd + 1]) < t[j])
hd++;
f[i & 1][j] = f[i - 1 & 1][q[hd]] + t[j] * (j - q[hd]) - (s[j] - s[q[hd]]);
while (hd < tl && slp(i - 1, q[tl], q[tl - 1]) > slp(i - 1, q[tl], j))
tl--;
q[++tl] = j;
}
}
printf("%lld", f[p & 1][m]);
return 0;
}