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; }