BZOJ 1109 POI2007 堆积木Klo LIS
题目大意:给定一个序列,能够多次将某个位置的数删掉并将后面全部数向左串一位,要求操作后a[i]=i的数最多
首先我们如果最后a[i]=i的数的序列为S
那么S满足随着i递增,a[i]递增(相对位置不变),i-a[i]单调不减(后面的不会比前面移动的少)
这是一个三维偏序问题
要是不看题解我就真去写CDQ分治了233
我们发现i=(i-a[i])+a[i]
也就是说假设一个序列满足i-a[i]单调不减且a[i]单调递增 那么i一定单调递增
于是就剩两维偏序了 LIS走起吧= =
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 100100 using namespace std; struct abcd{ int x,y; bool operator < (const abcd &a) const { if(x!=a.x) return x<a.x; return y<a.y; } }b[M]; int n,tot,ans,a[M]; namespace BIT{ int c[M]; void Update(int x,int y) { for(;x<=n;x+=x&-x) c[x]=max(c[x],y); } int Get_Ans(int x) { int re=0; for(;x;x-=x&-x) re=max(re,c[x]); return re; } } int main() { using namespace BIT; int i; cin>>n; for(i=1;i<=n;i++) { scanf("%d",&a[i]); if(i<a[i]) continue; b[++tot].x=i-a[i]; b[tot].y=a[i]; } sort(b+1,b+tot+1); for(i=1;i<=tot;i++) { int temp=Get_Ans(b[i].y-1)+1; ans=max(ans,temp); Update(b[i].y,temp); } cout<<ans<<endl; return 0; }