一,题目
# 饥饿的奶牛
## 题目描述
有一条奶牛冲出了围栏,来到了一处圣地(对于奶牛来说),上面用牛语写着一段文字。
现用汉语翻译为:
有 $N$ 个区间,每个区间 $x,y$ 表示提供的 $x\sim y$ 共 $y-x+1$ 堆优质牧草。你可以选择任意区间但不能有重复的部分。
对于奶牛来说,自然是吃的越多越好,然而奶牛智商有限,现在请你帮助他。
## 输入格式
第一行一个整数 $N$。
接下来 $N$ 行,每行两个数 $x,y$,描述一个区间。
## 输出格式
输出最多能吃到的牧草堆数。
## 样例 #1
### 样例输入 #1
```
3
1 3
7 8
3 4
```
### 样例输出 #1
```
5
```
## 提示
$1 \leq n \leq 1.5 \times 10^5$,$0 \leq x \leq y \leq 3 \times 10^6$。
链接:https://www.luogu.com.cn/problem/P1868
二,思路
先根据y值从小到大排序,再用动态规划来做,dp[i]代表前i个区间吃到的最多的牧草数,dp[i]可以从dp[i-1]转移,即不取第i个区间得到的牧草数,也可以从前面的dp来转移,即不取第i个区间得到的牧草数,从二者取最大值。
注,由于数据量过大,从前面的dp转移的算法需要优化,此时我们发现,如果当有一段区间的y刚好小于第i个区间的x,该dp和该区间前面的dp满足转移的条件,而后面的则会不满足,而该dp是前面所有dp的最优值,所以,只需要找到该dp所在的位置即可,所以可以用二分查找。
三,代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <cmath>
#include <deque>
#include <algorithm>
#include <vector>
using namespace std;
struct node
{
int x, y;
};
bool cmp(node n1, node n2)
{
return n1.y < n2.y;
}
signed main()
{
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
int N;
cin >> N;
deque<node> d(N + 1);
for (int i = 1; i <= N; ++i) cin >> d[i].x >> d[i].y;
sort(d.begin(), d.end(), cmp);
vector<int> dp(N + 1);
for (int i = 1; i <= N; ++i)
{
int l = 0, r = i;
while (l < r)
{
int mid = (l + r + 1) >> 1;
if (d[mid].y < d[i].x) l = mid;
else r = mid - 1;
}
dp[i] = max(dp[l] + d[i].y - d[i].x + 1, dp[i - 1]);
}
cout << dp[N];
return 0;
}