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