Jzoj4845 寻找

“我有个愿望,我希望穿越一切找到你。”
这是个二维平面世界,平面上有n个特殊的果实,我从(0,0)点出发,希望得到尽量多的果实,但是出于某种特殊的原因,我的运动方式只有三种(假设当前我在(x,y)):
1、我可以走到(x+1,y)
2、我可以走到(x,y+1)
3、我可以走到(x+1,y+1)

现在我需要你的帮助,帮我找出我最多能够得到多少个果实。


经典的二维dp,我们设f[i][j]表示。。。

非常水的一维dp,我们将所有的点按照x排序让后做一次最长不下降子序列就好了

这里比较老实地用了离散化+数据结构,比二分好想多了。。。2333333

#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 100010
#define mid (l+r>>1) 
using namespace std;
struct dt{ int x,y; } s[N];
int n,v[N],r[N],m,w[N<<2],f[N];
inline bool c1(dt a,dt b){ return a.x<b.x; }
void update(int l,int r,int x,int p,int k){
	if(l==r){ w[x]=max(w[x],k); return; }
	if(p<=mid) update(l,mid,x<<1,p,k);
	  else update(mid+1,r,x<<1|1,p,k);
	w[x]=max(w[x<<1],w[x<<1|1]);
}
int query(int l,int r,int x,int L,int R){
	if(L<=l && r<=R) return w[x];
	int Ans=0;
	if(L<=mid) Ans=max(Ans,query(l,mid,x<<1,L,R));
	if(mid<R) Ans=max(Ans,query(mid+1,r,x<<1|1,L,R));
	return Ans;
}
int main(){
	freopen("find.in","r",stdin);
	freopen("find.out","w",stdout);
	scanf("%d",&n);
	for(int x,y,i=1;i<=n;++i){
		scanf("%d%d",&x,&y);
		if(x<0 || y<0){ --n; --i; }
		else s[i]=(dt){x,y};
	}
	sort(s+1,s+1+n,c1);
	for(int i=1;i<=n;++i) v[i]=s[i].y;
	sort(v+1,v+1+n); m=unique(v+1,v+1+n)-v-1; 
	for(int i=1;i<=n;++i) r[i]=lower_bound(v+1,v+1+n,s[i].y)-v;
	for(int i=1;i<=n;++i){ f[i]=query(0,m,1,0,r[i])+1; update(0,m,1,r[i],f[i]); }
	printf("%d
",w[1]);
}

原文地址:https://www.cnblogs.com/Extended-Ash/p/9477264.html