P2889 [USACO07NOV]挤奶的时间Milking Time
奶牛Bessie在0~N时间段产奶。农夫约翰有M个时间段可以挤奶,时间段f,t内Bessie能挤到的牛奶量e。奶牛产奶后需要休息R小时才能继续下一次产奶,求Bessie最大的挤奶量。
错误日志: dp[i]转移的设计强制选择了第 i 个(自己还没发现)【然后后面发现又有问题唉】
Solution
先把 (R) 累积到右端点中, 排序
设 (dp[i]) 为考虑前 (i) 个区间, 第 (i) 个区间必选的最大获利
为什么要必选呢? 这样才能方便转移
容易写出方程:$$dp[i] = v[i] + max_{0 leq j leq i - 1}dp[j] [r_{j} leq l_{i}]$$
再回到为什么要必选, 这样才能有转移的判断条件(从必选的转移而来)
为了方便, 我们引入一个起点, 一个重点, 权值都为 (0) ,不影响结果而可以方便计算
Code
#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#include<climits>
#define LL long long
#define REP(i, x, y) for(int i = (x);i <= (y);i++)
using namespace std;
int RD(){
int out = 0,flag = 1;char c = getchar();
while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
return flag * out;
}
const int maxn = 2019;
int num, nr, R;
struct Node{int l, r, v;}I[maxn];
bool cmp(Node a, Node b){return a.l < b.l;}
int dp[maxn];
int main(){
num = RD(), nr = RD(), R = RD();
REP(i, 1, nr)I[i] = (Node){RD(), RD() + R, RD()};
sort(I + 1, I + 1 + nr, cmp);
I[0].r = -1026;//起点
I[nr + 1].l = num + R + 19;//终点
REP(i, 1, nr + 1){
REP(j, 0, i - 1){
if(I[j].r <= I[i].l)dp[i] = max(dp[i], dp[j] + I[i].v);
else dp[i] = max(dp[i], dp[j] - I[j].v + I[i].v);
}
}
printf("%d
", dp[nr + 1]);
return 0;
}