不难看出状态转移方程opt[i]=max(opt[j])+1(0<=j<i并且|a[j]-a[i] |<=d)
这样的复杂度是n平方,数据量最大10w,明显会TLE,看了网上的题解,可以用线段树来优化
线段树的每个叶子节点表示以i为结尾的最长子串长度,每一次查询之后更新 ans 为
max(ans, query(lower_bound, upper_bound) + 1);这样子就可以比较快的出答案了.
首先要一个数组b保存a数组排序去重复后的内容.然后按照b数组去建树.
然后要查询a[i]的区间只要二分查找一下a[i]-d,a[i]+d在b中的位置[x,y],这样[x,y]就是树的查询范围
连抄带猜写出来的,STL不错
#include <iostream>
#include <cstdio>
#include <memory.h>
#include <algorithm>
#include <functional>
using namespace std;
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
const int maxn=100010;
int segs[maxn<<2],a[maxn],b[maxn],n,d;
void build(int l,int r,int rt){
segs[rt]=0;
if(l==r)return;
int m=(l+r)>>1;
build(lson),build(rson);
}
int query(int L,int R,int l,int r,int rt){
if(L<=l&&r<=R){
return segs[rt];
}
int m=(l+r)>>1,ret=0;
if(L<=m)ret=max(ret,query(L,R,lson));
if(R>m)ret=max(ret,query(L,R,rson));
return ret;
}
void update(int l,int r,int rt,int v,int p){
if(l==r){
segs[rt]=max(v,segs[rt]);
return;
}
int m=(l+r)>>1,ret=0;
if(p<=m)update(lson,v,p);
else if(p>m)update(rson,v,p);
segs[rt]=max(segs[rt<<1],segs[rt<<1|1]);
}
int main(){
while (scanf("%d %d",&n,&d)==2){
for (int i=0;i<n;++i){
scanf("%d",&a[i]);
}
copy(a,a+n,b);
sort(b,b+n);
int bnd=unique(b,b+n)-b,ans=0;
build(0,bnd,1);
for (int i=0;i<n;++i){
int x=query(lower_bound(b,b+bnd,a[i]-d)-b,upper_bound(b,b+bnd,a[i]+d)-b-1,0,bnd,1);
update(0,bnd,1,x+1,lower_bound(b,b+bnd,a[i])-b);
ans=max(x+1,ans);
}
printf("%d\n",ans);
}
return 0;
}