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];
}
posted @ 2020-05-12 15:27  倾叶子佮  阅读(121)  评论(0编辑  收藏  举报