P1868 饥饿的奶牛

P1868 饥饿的奶牛

原题链接:传送门

分析

首先根据数据范围可知此问题的时间复杂度大概限制(O(n) / O(nlong_n)) 左右。由于是问的最多往贪心/dp方向思考

题目中指出可以选择任意区间但是这些区间不能有重叠的部分

对于一个区间[l, r],一共有两种可能

我们假设(f(i)) 表示前 i 个区间可以获取的最大价值

  • 选择这个区间

    如果我们要选择第 i 个区间,那么我们需要前 i - 1 个区间可以获取的最大价值

    (f(i) = f(k) + r - l + 1 (k 为上一个紧接着的区间))

  • 不选择这个区间

    (f(i) = f(i-1))

那么问题的关键就在于如何找到第一种情况中的 k 的下标。我们可以根据区间的 r 值对这个所有区间进行一次排序操作。

对于每一个区间([l,r]),我们只需要找到最后一个 k < r 的区间的下标

这个问题是一个线性dp问题其中串联使用了二分来搜索状态
从状态的定义到状态的寻找,从dp-->二分环环相扣。

AC 代码

C++ code

#include <bits/stdc++.h>

using namespace std;

const int N = 200005;

typedef long long ll;

struct node{
	int l, r;
}e[N];

ll f[N], n;


bool cmp(node a,node b)
{
	return a.r < b.r;
}

int main()
{
	cin >> n;

	for(int i = 1; i <= n; i ++)
	{
		cin >> e[i].l >> e[i].r;
	}

	sort(e + 1, e + 1 + n, cmp);

	for(int i = 1; i <= n; i ++)
	{
		ll w = e[i].r - e[i].l + 1;
		f[i] = w;
		int l = 1, r = i - 1;
		while(l < r)
		{
			int mid = l + r + 1 >> 1;
			if(e[mid].r < e[i].l)l = mid;
			else r = mid - 1;
		}
		if(e[l].r < e[i].l)
		{
			f[i] = max(f[i-1], f[i] + f[l]);
		} else {
			f[i] = max(f[i], f[i-1]);	
		}
	}
	cout << f[n] << endl;
	return 0;
}
原文地址:https://www.cnblogs.com/wlw-x/p/14724923.html