BZOJ1109 : [POI2007]堆积木Klo

f[i]表示第i个在自己位置上的最大值

则f[i]=max(f[j])+1

其中

j<i

a[j]<a[i]

a[i]-a[j]<=i-j -> j-a[j]<=i-a[i]

i-a[i]>=0

j-a[j]>=0

发现后两项可以推出第一项,所以是一个LIS问题,排序后树状数组优化DP即可,时间复杂度$O(n\log n)$。

 

#include<cstdio>

#include<algorithm>

#define N 100010

int n,i,j,k,a[N],b[N],bit[N],t,f[N],ans;

struct E{int x,y;E(){}E(int _x,int _y){x=_x,y=_y;}}e[N];

inline bool cmp(E a,E b){return a.x<b.x;}

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 ins(int x,int y){for(;x<=n;x+=x&-x)if(bit[x]<y)bit[x]=y;}

inline void ask(int x){for(;x;x-=x&-x)if(t<bit[x])t=bit[x];}

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(j),e[i]=E(j,i-j),b[i]=i-j;

  std::sort(e+1,e+n+1,cmp),std::sort(b+1,b+n+1);

  for(i=1;i<=n;i=j){

    for(j=i;j<=n&&e[j].x==e[i].x;j++)if(e[j].y>=0){

      t=0,ask(e[j].y=lower(e[j].y));

      if(ans<(f[j]=++t))ans=t;

    }

    for(j=i;j<=n&&e[j].x==e[i].x;j++)if(e[j].y>=0)ins(e[j].y,f[j]);

  }

  return printf("%d",ans),0;

}

  

你可能感兴趣的:(2007)