信息学奥赛一本通 ybt 1608:【 例 3】任务安排 3 | 洛谷 P5785 [SDOI2012] 任务安排
【题目链接】
ybt 1608:【 例 3】任务安排 3
洛谷 P5785 [SDOI2012] 任务安排
【题目考点】
1. 动态规划:斜率优化动规
2. 单调队列
3. 二分答案
【解题思路】
与本题题面相同但问题规模不同的题目:
信息学奥赛一本通 1607:【 例 2】任务安排 2 | 洛谷 P10979 任务安排 2
本题相比上题只有
t
i
t_i
ti的数值范围从
t
i
≤
2
8
t_i\le 2^8
ti≤28,变为
∣
t
i
∣
≤
2
8
|t_i| \le 2^8
∣ti∣≤28,也就是
−
2
8
≤
t
i
≤
2
8
-2^8 \le t_i \le 2^8
−28≤ti≤28
斜率优化相关内容已在上题中有详细解释,本题不再赘述。请先看上题题解,而后再看本题题解。
本题中
t
i
t_i
ti可能是负数,求出的前缀和
T
i
T_i
Ti也可能是负数。
随着
i
i
i的增大
T
i
T_i
Ti不再是单调递增的,直线斜率
K
=
T
i
+
s
K=T_i+s
K=Ti+s随着
i
i
i的增大也不再是单调递增的。因此上题题解中8. 决策点队头出队中所述的方法不再适用。本题需要维护所有下凸壳上的决策点。
已知决策点比较条件为:
在
C
j
1
<
C
j
2
C_{j_1}<C_{j_2}
Cj1<Cj2的前提下:
- 如果 k ( j 1 , j 2 ) > K k(j_1,j_2) > K k(j1,j2)>K,那么决策点 j 1 j_1 j1优于 j 2 j_2 j2
- 如果 k ( j 1 , j 2 ) < K k(j_1,j_2) < K k(j1,j2)<K,那么决策点 j 2 j_2 j2优于 j 1 j_1 j1
决策点集的下凸壳上的所有决策点按
C
j
C_j
Cj从小到大记为
q
l
,
q
l
+
1
,
.
.
.
,
q
r
q_l,q_{l+1},...,q_r
ql,ql+1,...,qr,保存在一个单调队列中,相邻点连线的斜率是单调递增的:
k
(
q
l
,
q
l
+
1
)
<
k
(
q
l
+
1
,
q
l
+
2
)
<
.
.
.
<
k
(
q
r
−
1
,
q
r
)
k(q_l,q_{l+1})<k(q_{l+1},q_{l+2})<...<k(q_{r−1},q_r)
k(ql,ql+1)<k(ql+1,ql+2)<...<k(qr−1,qr)
那么从
q
l
q_l
ql看到
q
r
q_r
qr,找到第一个满足
k
(
q
m
,
q
m
+
1
)
≥
K
k(q_m,q_{m+1})≥K
k(qm,qm+1)≥K的决策点
q
m
q_m
qm,
q
m
q_m
qm就是最优决策点。
如果没有满足条件的点,则选择队列最后一个点
q
r
q_r
qr为最优决策点。
该过程可以通过二分答案完成
- 答案变量: q q q数组下标m,初始范围 [ l , r ] [l, r] [l,r]
- 最值:求最小值
- 满足条件: k ( q m , q m + 1 ) ≥ K k(q_m,q_{m+1})≥K k(qm,qm+1)≥K
如果存在满足条件的决策点,返回二分答案的结果m,取最优决策点
q
m
q_m
qm。
如果不存在满足条件的决策点,二分答案的结果就是初始范围的右端点r,此时返回r,取到的最优决策点是
q
r
q_r
qr
条件
k
(
q
m
,
q
m
+
1
)
≥
K
k(q_m,q_{m+1})≥K
k(qm,qm+1)≥K经过十字相乘后变为
(
d
p
q
m
+
1
−
d
p
q
m
)
≥
K
(
C
q
m
+
1
−
C
q
m
)
(dp_{q_{m+1}}-dp_{q_m})\ge K (C_{q_{m+1}}-C_{q_m})
(dpqm+1−dpqm)≥K(Cqm+1−Cqm)
算法时间复杂度为
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)
图示:
一种可能的情况:
i为1时,直线斜率为
K
1
K_1
K1,第一个满足条件的是
k
(
q
3
,
q
4
)
≥
K
1
k(q_3,q_4)\ge K_1
k(q3,q4)≥K1,最优决策点为
q
3
q_3
q3
i为2时,直线斜率为
K
2
K_2
K2,第一个满足条件的是
k
(
q
2
,
q
3
)
≥
K
2
k(q_2,q_3)\ge K_2
k(q2,q3)≥K2,最优决策点为
q
2
q_2
q2
i为3时,直线斜率为
K
3
K_3
K3,没有满足条件的点,最优决策点为最后一个点
q
5
q_5
q5
【题解代码】
解法1:斜率优化动规,二分查找最优决策点 O ( n l o g n ) O(nlogn) O(nlogn)
#include<bits/stdc++.h>
using namespace std;
#define N 300005
long long n, s, t[N], c[N], T[N], C[N], dp[N];//dp[i]:前i个任务的所有子段划分方案中,执行任务的费用 加上当前方案下每批任务的启动时间对后续任务产生的费用加和 最小的划分方案的费用
int q[N];
int binarySearch(int l, int r, int k)//通过二分查找找到第一个满足k(q[m], q[m+1])>=k的m,返回m。找不到满足条件的点,会返回r。
{
while(l < r)
{
int m = (l+r)/2;
if((dp[q[m+1]]-dp[q[m]]) >= k*(C[q[m+1]]-C[q[m]]))
r = m;
else
l = m+1;
}
return l;
}
int main()
{
int l = 1, r = 0;//单调队列队头队尾下标
cin >> n >> s;
for(int i = 1; i <= n; ++i)
{
cin >> t[i] >> c[i];
T[i] = T[i-1]+t[i];
C[i] = C[i-1]+c[i];
}
q[++r] = 0;//加入(C[0],dp[0])点
for(int i = 1; i <= n; ++i)
{
int b = binarySearch(l, r, T[i]+s);
dp[i] = dp[q[b]]-(T[i]+s)*C[q[b]]+T[i]*C[i]+s*C[n];
while(l < r && (dp[i]-dp[q[r]])*(C[q[r]]-C[q[r-1]]) <= (C[i]-C[q[r]])*(dp[q[r]]-dp[q[r-1]]))
--r;
q[++r] = i;
}
cout << dp[n];
return 0;
}