Blog of RuSun

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

P5785 [SDOI2012]任务安排

P5785 [SDOI2012]任务安排

与另一道任务安排唯一不一样的地方是可能存在 $t _ i < 0$ ,这意味着斜率不再具有单调性。因此单调队列中斜率小于 $k$ 的不再能直接删除。而凸包中的边的斜率是有单调性的,所以我们二分这些边,找到第一条相切的边。

查看代码
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 <iostream>
#include <cstdio>
#include <climits>
#define inf INT_MAX
using namespace std;
typedef long long LL;
const int N = 3e5 + 10;
int n;
int hd = 1, tl = 0;
LL q[N];
LL s, st[N], sc[N], f[N];
int get (int i, int k)
{
int l = hd, r = tl;
while (l < r)
{
int mid = l + r>> 1;
if (f[q[mid + 1]] - f[q[mid]] <= k * (sc[q[mid + 1]] - sc[q[mid]]))
l = mid + 1;
else
r = mid;
}
return q[l];
}
int main ()
{
cin >> n >> s;
for (int i = 1; i <= n; i++)
{
LL a, b;
cin >> a >> b;
st[i] = st[i - 1] + a;
sc[i] = sc[i - 1] + b;
}
for (int i = 1; i <= n; i++)
f[i] = inf;
q[++tl] = 0;
for (int i = 1; i <= n; i++)
{
int p = get(i, s + st[i]);
f[i] = f[p] - (s + st[i]) * sc[p] + st[i] * sc[i] + s * sc[n];
while (hd < tl && (f[q[tl]] - f[q[tl - 1]]) * (sc[i] - sc[q[tl]]) >= (f[i] - f[q[tl]]) * (sc[q[tl]] - sc[q[tl - 1]]))
tl--;
q[++tl] = i;
}
cout << f[n];
return 0;
}