洛谷P1868 饥饿的奶牛
题目链接
我们要在这个区间中选出任意多个非重叠的区间,使得选出来的区间总长度最长。我们可以从最左端的位置开始枚举,一直枚举到最远的位置,我们用\(dp[i]\)来表示从\(1\)开始以\(i\)结尾的这一段没有重叠区间的最长长度。我们可以发现,只要我们枚举的点是在上一个点的后面,那么前面的最远距离其实是固定的,因为我们候选出来的点并不会对之前选出来的区间造成影响,也就是不具有后效性,我们可以考虑使用线性\(DP\)去求解这个问题。每一次的状态转移方程为: $$dp[i] = \max(dp[i - 1], dp[j] + w[j,i])$$这个地方的\(w[j,i]\)表示的是从前一个\(j\)点选到\(i\)点的这一段合法的区间长度也就是\(i - j\)
#include <bits/stdc++.h>
using i64 = long long;
#define rep(i, a, n) for (int i = a; i < n; i ++ )
#define per(i, a, n) for (int i = n - 1; i >= a; i -- )
#define SZ(a) (int(a.size()))
#define pb push_back
#define all(a) a.begin(), a.end()
//head
int n;
std::vector<int> br[3000010];
int dp[3000010];
int main() {
scanf("%d", &n);
int res = 0;
rep(i,0,n) {
int l, r;
scanf("%d%d", &l, &r);
br[r].pb(l - 1);
res = std::max(res, r);
}
rep(i,1,res + 1) {
dp[i] = dp[i - 1];
for (int j = 0; j < SZ(br[i]); j ++ ) {
int ver = br[i][j];
dp[i] = std::max(dp[i], dp[ver] + i - ver);
}
}
printf("%d\n", dp[res]);
return 0;
}