题意:给一个数字序列,问你长度大于2的且相邻两个数的差的绝对值不大于d的情况对9901取余
思路:看了根本不会,都没想到是线段树的题目,弱哭~~~,看了大牛们的题解,算是知道怎么回事了,对于当前的数A,那么以它为最后一个元素可以组成的情况是A-d到A+d的和,也可以这样想,A-d的已经组成了m种情况,那么在不影响小于d的情况下,可以直接将A放到A-d组成的左右序列中,那么直接加就可以了,而后更新A可以组成的情况,数据太大还需要离散化,然后二分找一下A-d和A+d的位置,数据可能没有这两个位置,那么找到第一个大于等于A-d和第一个小于等于A+d的位置更新就行,且不会影响结果,自己写个数据看看就会懂了 PS:多校的题目好难,想着一天刷一套自己部分的题目,而且太难的直接放弃(毕竟太弱),还是有点难以完成啊
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3fll;
const int maxn=100010;
const int mod=9901;
int num[maxn<<2],A[maxn],B[maxn];
int n,m;
int lower_1(int val,int k){
int le=0,ri=k;
while(ri-le>1){
int mid=(le+ri)>>1;
if(B[mid]<=val) le=mid;
else ri=mid;
}
return le+1;
}
void update(int pos,int add,int le,int ri,int node){
if(le==ri){
num[node]+=add;
num[node]%=mod;
return ;
}
int t=(le+ri)>>1;
if(pos<=t) update(pos,add,le,t,node<<1);
else update(pos,add,t+1,ri,node<<1|1);
num[node]=(num[node<<1]+num[node<<1|1])%mod;
}
int query(int l,int r,int le,int ri,int node){
if(l<=le&&ri<=r) return num[node];
int ans=0,t=(le+ri)>>1;
if(l<=t) ans+=query(l,r,le,t,node<<1);
if(r>t) ans+=query(l,r,t+1,ri,node<<1|1);
return ans%mod;
}
int main(){
while(scanf("%d%d",&n,&m)!=-1){
int k=1,ans=0;
memset(num,0,sizeof(num));
for(int i=0;i<n;i++){
scanf("%d",&A[i]);
B[i]=A[i];
}
sort(B,B+n);
for(int i=1;i<n;i++){
if(B[i]!=B[i-1]) B[k++]=B[i];
}
for(int i=0;i<n;i++){
int le=lower_bound(B,B+k,A[i]-m)-B+1;
int ri=lower_1(A[i]+m,k);
int pos=lower_bound(B,B+k,A[i])-B+1;
int ans1=query(le,ri,1,k,1);
ans=(ans+ans1)%mod;
update(pos,ans1+1,1,k,1);
}
printf("%d\n",ans);
}
return 0;
}