[IOI2002]任务安排
Description
N个任务排成一个序列在一台机器上等待完成(顺序不得改变),这N个任务被分成若干批,每批包含相邻的若干任务。从时刻0开始,这些任务被分批加工,第i个任务单独完成所需的时间是Ti。在每批任务开始前,机器需要启动时间S,而完成这批任务所需的时间是各个任务需要时间的总和(同一批任务将在同一时刻完成)。每个任务的费用是它的完成时刻乘以一个费用系数Fi。请确定一个分组方案,使得总费用最小。
例如:S=1;T={1,3,4,2,1};F={3,2,3,3,4}。如果分组方案是{1,2}、{3}、{4,5},则完成时间分别为{5,5,10,14,14},费用C={15,10,30,42,56},总费用就是153。
Input
第一行是N(1<=N<=5000)。
第二行是S(0<=S<=50)。
下面N行每行有一对数,分别为Ti和Fi,均为不大于100的正整数,表示第i个任务单独完成所需的时间是Ti及其费用系数Fi。
Output
一个数,最小的总费用。
Sample Input
5
1
1 3
3 2
4 3
2 3
1 4
Sample Output
153
Source
动态规划 ,斜率优化
Solution
简单的DP问题,可以考虑斜率优化等,但是因为数据不大O(n^2)也可以过的
考虑到对于每一种花费情况,显然每一个元件是否处于该批次只对其后面的元件有影响,于是可以考虑有后缀和记录花费时间及代价,然后倒序更新dp值,最后答案在dp[1]上,注意初始化以及更新的范围:
dp[n + 1] = 0;
for (int i = n; i >= 1; --i)
for (int j = i + 1; j <= n + 1; ++j)
dp[i] = min(dp[i], dp[j] + sumf[i] * (sumt[i] - sumt[j] + s));
还可以用前缀和处理,找到一个O(n^3)的递推关系式,然后加一个斜率优化
Code
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <stack>
#include <map>
#include <vector>
#include <queue>
#define L 5010
#define inf 1000000009
#define LL long long
using namespace std;
int n, s;
LL f[L], t[L], sumf[L], sumt[L], dp[L];
int main() {
freopen("batch.in", "r", stdin);
freopen("batch.out", "w", stdout);
memset(dp, inf, sizeof(dp));
scanf("%d %d", &n, &s);
for (int i = 1; i <= n; ++i) scanf("%lld %lld", &t[i], &f[i]);
for (int i = n; i >= 1; --i) sumt[i] = sumt[i + 1] + t[i], sumf[i] = sumf[i + 1] + f[i];
dp[n + 1] = 0;
for (int i = n; i >= 1; --i)
for (int j = i + 1; j <= n + 1; ++j)
dp[i] = min(dp[i], dp[j] + sumf[i] * (sumt[i] - sumt[j] + s));
printf("%lld\n", dp[1]);
return 0;
}
Summary
考试的时候考虑到了每一个元件的影响范围是取决于本组在该元件后的元件,所以有考虑用后缀数组,大概算了算递推公式和标程大概差不多,然而只剩下不到十分钟了,于是……
后面看了下题解,但是一直没有处理好初始化以及范围的问题,后来受标程的启发将初始值后移了一位就A了