题目分析:
DP,设
f
[
i
]
f[i]
f[i]表示答案序列以第i个点结尾的最长长度,
a
[
i
]
a[i]
a[i]为第i个点的数。
那么当
i
≥
a
[
i
]
i\ge a[i]
i≥a[i]时,有
f
[
i
]
=
f
[
j
]
+
1
f[i]=f[j]+1
f[i]=f[j]+1,这个转移需要满足
a
[
i
]
≥
a
[
j
]
且
i
−
j
>
=
a
[
i
]
−
a
[
j
]
a[i]\ge a[j]且i-j>=a[i]-a[j]
a[i]≥a[j]且i−j>=a[i]−a[j]
移一下项就是
a
[
i
]
≥
a
[
j
]
且
i
−
a
[
i
]
≥
j
−
a
[
j
]
a[i]\ge a[j]且i-a[i]\ge j-a[j]
a[i]≥a[j]且i−a[i]≥j−a[j],可以看出,这样的转移已经保证了
i
≥
j
i\ge j
i≥j,那么只需要按a[i]排序,把i-a[i]放进树状数组里面,每次找最大值即可。
Code:
#include<cstdio>
#include<cctype>
#include<algorithm>
#define maxn 100005
char cb[1<<15],*cs,*ct;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<15,stdin),cs==ct)?0:*cs++)
inline void read(int &a){
char c;while(!isdigit(c=getc()));
for(a=c-'0';isdigit(c=getc());a=a*10+c-'0');
}
using namespace std;
int n,ans;
struct node{
int x,id;
bool operator < (const node &p)const{return x==p.x?id>p.id:x<p.x;}
}a[maxn];
int arr[maxn];
void upd(int i,int d){for(;i<=n;i+=i&-i) arr[i]=max(arr[i],d);}
int qmax(int i){int s=0;for(;i;i-=i&-i) s=max(s,arr[i]);return s;}
int main()
{
read(n);
for(int i=1;i<=n;i++) read(a[i].x),a[i].id=i;
sort(a+1,a+1+n);
for(int i=1,x;i<=n;i++) if(a[i].id>=a[i].x) ans=max(ans,x=qmax(a[i].id-a[i].x+1)+1),upd(a[i].id-a[i].x+1,x);
printf("%d",ans);
}