BZOJ2924 : [Poi1998]Flat broken lines
首先旋转坐标系
$x'=x-y$
$y'=-x-y$
则对于一个点,它下一步可以往它左上角任意一个点连线。
根据Dilworth定理,答案=这个偏序集最长反链的长度。
设f[i]为到i点为止的最长反链长度,则
f[i]=max(f[j])+1,j在i的左下角
按x坐标排序后用树状数组优化DP即可,时间复杂度$O(n\log n)$。
#include<cstdio> #include<algorithm> #define N 30010 int n,i,j,x,y,b[N],bit[N],f[N],ans; struct P{int x,y;}a[N]; inline bool cmp(P a,P b){return a.x<b.x;} inline void up(int&a,int b){if(a<b)a=b;} inline void ins(int x,int y){for(;x<=n;x+=x&-x)up(bit[x],y);} inline int ask(int x){int t=0;for(;x;x-=x&-x)up(t,bit[x]);return t;} inline int lower(int x){ int l=1,r=n,mid,t; while(l<=r)if(b[mid=(l+r)>>1]<=x)l=(t=mid)+1;else r=mid-1; return t; } inline void read(int&a){char c;while(!(((c=getchar())>='0')&&(c<='9')));a=c-'0';while(((c=getchar())>='0')&&(c<='9'))(a*=10)+=c-'0';} int main(){ for(read(n),i=1;i<=n;i++)read(x),read(y),a[i].x=x-y,a[i].y=b[i]=-x-y; for(std::sort(a+1,a+n+1,cmp),std::sort(b+1,b+n+1),i=1;i<=n;i=j){ for(j=i;j<=n&&a[j].x==a[i].x;j++)up(ans,f[j]=ask((a[j].y=lower(a[j].y))-1)+1); for(j=i;j<=n&&a[j].x==a[i].x;j++)ins(a[j].y,f[j]); } return printf("%d",ans),0; }