开始看觉得是dp,复杂度O(n^2)会超时就没做,应该是用线段树或者树状数组,加上离散化和二分法优化。
你需要一个dp[i]数组,存储的是以i为结尾的个数,结果就是dp[]之和.
离散化的部分是用一个离散化结构体,最终的hash0[]数组里存的就是num[i]的大小序号
其次便是用到了线段树的区间更新和单点查询。
二分法用在了查询与当前点符合的前部和尾部。
#include<bits/stdc++.h>
using namespace std;
const int maxn = 100010;
int dp[maxn],num[maxn],hash0[maxn];
struct Discrete{
int n,index;
bool operator < (const Discrete& rhs) const {
return n < rhs.n;
}
}C[maxn];
struct Segment {
int l,r,mid;
int num;
}T[4*maxn];
void build(int l,int r,int k){
T[k].l=l,T[k].r=r,T[k].num=0;
T[k].mid = (l+r)>>1;
if(l==r) return ;
build(l,T[k].mid,2*k);
build(T[k].mid+1,r,2*k+1);
}
int find_(int aim,int k){
int ans=0;
if(T[k].l==T[k].r && T[k].l==aim) return T[k].num%9901;
if(T[k].l<=aim && aim<=T[k].r){
ans+=T[k].num;
if(aim<=T[k].mid) ans+=find_(aim,2*k);
else ans+=find_(aim,2*k+1);
}
return ans%9901;
}
void update(int l,int r,int dir,int k){
if(T[k].l==l && T[k].r==r) { T[k].num+=dir; T[k].num%9901; return ; }
if(r <= T[k].mid) update(l,r,dir,2*k);
else if(l>T[k].mid) update(l,r,dir,2*k+1);
else {
update(l,T[k].mid,dir,2*k);
update(T[k].mid+1,r,dir,2*k+1);
}
}
int main()
{
int n,d,ans,l,r;
while(~scanf("%d%d",&n,&d))
{
build(1,n,1);
for(int i=1;i<=n;i++) {
scanf("%d",&num[i]);
C[i].n=num[i]; C[i].index=i;
}
sort(C+1,C+n+1);
for(int i=1;i<=n;i++) hash0[C[i].index]=i;
memset(dp,0,sizeof(dp));
ans=0;
for(int i=1;i<=n;i++){
dp[i]=find_(hash0[i],1);
ans += dp[i];
ans%=9901;
int low=1,up=hash0[i],mid=(low+up)>>1;
while(low<=up){
if(C[mid].n-num[i]< -d) low=mid+1;
else up=mid-1;
mid=(low+up)>>1;
}
l=low;
low=hash0[i],up=n,mid=(low+up)>>1;
while(low<=up){
if(C[mid].n-num[i]<=d) low=mid+1;
else up=mid-1;
mid=(low+up)>>1;
}
r=low-1;
update(l,r,(dp[i]+1)%9901,1);
}
printf("%d\n",ans);
}
return 0;
}