斜率优化dp
P2365 任务安排
这道题因为数据量不大,不需要用到斜率优化dp也能过(解法三用了斜率优化dp),但后续的 P5785 虽然题意不变,但数据范围变大了,需要用到斜率优化dp来解决,所以就先用较简单的做法介绍一下这道题。
洛谷:P2365 任务安排
题目描述:
有 N 个任务排成一个序列在一台机器上等待执行,它们的顺序不得改变。机器会把这 N 个任务分成若干批,每一批包含连续的若干个任务。从时刻0开始,任务被分批加工,执行第 i 个任务所需的时间是 Ti。
另外,在每批任务开始前,机器需要 S 的启动时间,故执行一批任务所需的时间是启动时间 S 加上每个任务所需时间之和。一个任务执行后,将在机器中稍作等待,直至该批任务全部执行完毕。也就是说,同一批任务将在同一时刻完成。每个任务的费用是它的完成时刻乘以一个费用系数 Ci。
请为机器规划一个分组方案,使得总费用最小。
输入格式:
第一行包含整数 N。
第二行包含整数 S。
接下来N行每行有一对整数,分别为 Ti 和 Ci,表示第 i 个任务单独完成所需的时间 Ti 及其费用系数 Ci。
输出格式:
输出一个整数,表示最小总费用。
数据范围:
1 ≤ N ≤ 5000
0 ≤ S ≤ 50
1 ≤ Ti,Ci ≤ 100
解法一 O(N^3):
求出T,C的前缀和sumT,sumC。即: s u m T [ i ] = ∑ j = 1 i T [ j ] sumT[i] = \sum_{j=1}^{i}T[j] sumT[i]=∑j=1iT[j], s u m C [ i ] = ∑ j = 1 i C [ j ] sumC[i] = \sum_{j = 1} ^ {i}C[j] sumC[i]=∑j=1iC[j]
设F[i, j]表示把前i个任务分成 j 批执行的最小费用,则第 j 批任务完成的时间就是j * s + sumT[i]。以第j - 1批和第j批任务的分界点为DP的“决策”,状态转移方程为:
F [ i , j ] = min 0 ≤ k < j { F [ k , j − 1 ] + ( s ∗ j + s u m T [ i ] ) ∗ ( s u m C [ i ] − s u m C [ k ] } F[i, j] = \min_{0{\leq}k<j} \{F[k, j - 1] + (s * j + sumT[i]) * (sumC[i] - sumC[k]\} F[i,j]=0≤k<jmin{
F[k,j−1]+(s∗j+sumT[i])∗(sumC[i]−sumC[k]}
该解法的时间复杂度为O(N3)。
解法二:O(N^2):
本题并没有规定需要把任务分成多少批,在上一个解法中之所以需要批数 j , 是因为我们需要知道机器启动了多少次(每次启动都要S单位时间),从而计算出 i 所在的一批任务的完成时刻。
事实上,在执行一批任务时,我们不容易直接得知在此之前机器启动过几次。但我们知道,机器因执行这批任务而花费的启动时间S,会累加到在此之后所有任务的完成时刻上。设 F[i] 表示把前 i 个任务分成若干批执行的最小费用,状态转移方程为:
F [ i ] = min 0 ≤ j < i { F [ j ] + s u m T [ i ] ∗ ( s u m C [ i ] − s u m C [ j ] ) + s ∗ ( s u m C [ N ] − s u m C [ j ] ) } F[i] = \min_{0{\leq}j<i} \{F[j] + sumT[i] * (sumC[i] - sumC[j]) + s * (sumC[N] - sumC[j])\} F[i]=0≤j<imin{
F[j]+sumT[i]∗(sumC[i]−sumC[j])+s∗(sumC[N]−sumC[j])}
在上式中,第 j + 1 ~ i个任务在同一批内完成,sumT[i] 是忽略机器的启动时间
时,这批任务的完成时刻。因为这批任务的执行,机器的启动时间S会对第j + 1个之后的所有任务产生影响,故我们把这部分补充到费用中。
也就是说,我们没有直接求出每批任务的完成时刻,而是在一批任务“开始”对后续任务产生影响时,就先把费用累加到答案中。这是一种名为“费用提前计算”的经典思想。
该解法的时间复杂度为0 (N2) 。
代码如下:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int read(){
int x, f = 1;
char ch;
while(ch = getchar(), ch < '0' || ch > '9') if(ch == '-') f = -