P1868 饥饿的奶牛

永久打开的传送门

(color{Red}{------------------分割线----------------------------})

(感觉是非常巧妙的DP。。。。)

(先按照区间右端点进行排序)

(f[i]表示前i个区间中,最后一个区间选的i,最大有多少草)

(f[i]=max(f[i-1],f[j]+a[i].tail-a[i].head+1);//j表示尾小于当前区间头且f最大的区间下标)

(这是O(n^2)的,但是找j可以用二分优化成O(nlogn))(下面还有O(n)算法)$

#include <bits/stdc++.h>
using namespace std;
const int maxn=150009;
int n,f[maxn];
struct p{
	int x,y,val;
}a[maxn];
bool com(p a,p b){
	return a.y<b.y;
}
int find(int l,int r,int key)
{
	int ans=0;
	while(r>=l)
	{
		int mid=(l+r)/2;
		if(a[mid].y<key)	ans=mid,l=mid+1;
		else	r=mid-1;
	}
	return ans;
}
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d",&a[i].x,&a[i].y);
		a[i].val=a[i].y-a[i].x+1;
	}
	sort(a+1,a+1+n,com);
	for(int i=1;i<=n;i++)
	{
		int j=find(1,i-1,a[i].x);
		f[i]=max(f[i-1],f[j]+a[i].val);
	}
	cout<<f[n];
	return 0;
}

(还可以直接枚举每个y坐标,那么转移就是从区间右端点刚好是枚举值的点转移过来)

#include <bits/stdc++.h>
using namespace std;
const int maxn=3000010;
vector<int>bb[maxn];
int maxx,f[maxn];
int main()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	{
		int l,r;
		scanf("%d%d",&l,&r);
		bb[r].push_back(l);
		maxx=max(maxx,r);
	}
	for(int i=1;i<=maxx;i++)
	{
		f[i]=f[i-1];//不选当前区间 
		for(int j=0;j<bb[i].size();j++)
		{
			int b=bb[i][j];
			f[i]=max(f[i],f[b-1]+i-b+1);
		}
	}
	cout<<f[maxx];
}
原文地址:https://www.cnblogs.com/iss-ue/p/12876503.html