题意:给一个数字序列,问你长度大于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; }
时间: 2024-10-07 19:52:25