题意:对于已知数组a,求子区间个数满足最大最小值的差值不超过k的子区间个数
思路:从头开始遍历,记录最大最小值得位置和值,当最大最小值超过k时,表示前面的区间可以自由选择连续区间都满足要求,然后可以继续从靠左的最大值或者最小值的下一个位置开始遍历,重新记录最大最小值。重点是记录上一个选定的区间,当后面选择的区间与前面选择的区间有重合时,要减去重合的部分,并且最后了要统计一下
代码:
#include<bits/stdc++.h>
using namespace std;
#define mod 1000000007
int n,k,T,a[100005];
long long ans,l,r,x,y,minn,maxx,px,pn,re,en;
int main()
{
scanf("%d",&T);
while(T--)
{
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]);
}
l=r=ans=0;
minn=0x3f3f3f3f;
maxx=-1;
re=1;
for(int i=1;i<=n;i++)
{//cout<<i<<" "<<a[i]<<" "<<maxx<<" "<<minn<<" !!"<<endl;
if(maxx-a[i]>=k||a[i]-minn>=k)
{
en=i-1;
if(re<=r)
{
x=r-re+1;
}
else x=0;
ans+=(en-re+2)*(en-re+1)/2;
ans-=x*(x+1)/2;
//cout<<i<<" "<<ans<<" "<<re<<" "<<en<<" "<<endl;
l=re;r=en;
re=min(pn,px)+1;
i=re;
minn=0x3f3f3f3f;
maxx=-0x3f3f3f3f;
}
if(a[i]<minn) {minn=a[i];pn=i;}
if(a[i]>maxx) {maxx=a[i];px=i;}
}
en=n;
if(re<=r)
{
x=r-re+1;
}
else x=0;
ans+=(en-re+2)*(en-re+1)/2;
ans-=x*(x+1)/2;
printf("%lld\n",ans);
}
}