方法:单调队列区间最大最小
错误记录(本地写错)的原因:写成每次试着扩展右端点,却难以正确地处理"在多扩展右端点之后减去多扩展的部分"这一任务(分类太多,例如:由于无法扩展有端点有可能是因为有端点已经到达最右端,也可能是因为最大最小差超过要求)。显然那样写没有每次扩展一个右端点,并从左侧开始删直到重新使序列符合标准(two_pointers?)方便。
1 #include<cstdio> 2 #include<algorithm> 3 using namespace std; 4 int a[100100],qmin[101000],qmax[101000],n,m,k,lmin,rmin,lmax,rmax,l,r,maxans; 5 int main() 6 { 7 int i; 8 while(scanf("%d%d%d",&n,&m,&k)==3) 9 { 10 lmin=rmin=lmax=rmax=maxans=0;l=1; 11 for(i=1;i<=n;i++) 12 scanf("%d",&a[i]); 13 for(r=1;r<=n;r++) 14 { 15 while(lmin<rmin&&a[qmin[rmin-1]]>=a[r]) --rmin; 16 qmin[rmin++]=r; 17 while(lmax<rmax&&a[qmax[rmax-1]]<=a[r]) --rmax; 18 qmax[rmax++]=r; 19 while(l<=r&&(a[qmax[lmax]]-a[qmin[lmin]]>k)) 20 { 21 if(lmin<rmin&&qmin[lmin]<=l) lmin++; 22 if(lmax<rmax&&qmax[lmax]<=l) lmax++; 23 l++; 24 } 25 if(l<=r&&a[qmax[lmax]]-a[qmin[lmin]]>=m) 26 maxans=max(maxans,r-l+1); 27 } 28 printf("%d ",maxans); 29 } 30 return 0; 31 }