loongint的花篮——双方向单调栈
Loongint的花篮
【Description】
Loongint要和MM结婚了。在两人的走进礼堂的红地毯两侧,需要摆一些装饰用的花篮,有一些不同高度的花篮,现在这些花篮被Loongint依照自己的美学观念编号为S1,S2,S3…Sn(两侧的花篮高度一样)。可Loongint的MM对这些花篮的摆放方式有不同的看法,她觉得满足以下条件的花篮摆放才是最好的。
如果对于区间[Si,Sj](1<=i<j<=n)中任意的花篮都比Si高且比Sj低,那么这个区间称为一个美学区间。对于所有的美学区间,其长度(定义为j-i)都必须小于等于k,如果有长度大于k的美学区间,MM就会不高兴,Loongint就会有麻烦…
【Input】
第一行为m。表示有m组测试数据。
对于每一组:
第一行n,k,分别表示花篮的数量和美学区间的最大长度。
第二行为n个数,分别表示S1,S2,S3…Sn的值。
【Output】
如果根本不存在美学区间,输出-1。
如果存在美学区间,那么如果任意区间的长度都小于等于k,那么输出最大的长度,否则输出最大长度比k大多少(MaxLength-k)。
【Sample Input】
3
4 2
5 4 3 6
4 1
6 5 4 3
4 2
1 2 3 4
【Sample Output】
1
-1
1
【Hint】
对于30%的测试数据,1<=n<=100。
对于60%的测试数据,1=<n<=5555。
对于100%的测试数据,1<=n<=100000,0<Si<=100000,1=<m<=3。
分析:
这道题的题意简述就是
求最长的区间,使区间中的元素都比左端点大,比右端点小。
说明存在单调的性质,
想到用单调栈,具体的实现其实挺难的。
其实我知道的解法有两种,
1.双方向单调栈,
2.一遍单调栈,一遍RMQ,
这里我用的是解法一。
具体的见代码中的简析。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | program baskets; var flag,i,b,j,n,kk,t,m,k,loc: longint ; x,q,left,right,ans,len: longint ; a: array [ 0..100010 ] of longint ; s,w,r,l: array [ 0..100010 ] of longint ; procedure doing; var i,j: longint ; begin fillchar(a,sizeof(a), 0 ); fillchar(s,sizeof(s), 0 ); fillchar(w,sizeof(w), 0 ); ans:= 0 ;len:= 0 ;b:= 0 ;i:= 0 ;j:= 0 ; //初始化 readln(n,k); a[ 0 ]:=maxlongint; a[n+ 1 ]:=-maxlongint; for i:= 1 to n do read(a[i]); //初始化 t:= 1 ; s[ 1 ]:=a[ 1 ];w[ 1 ]:= 1 ; for i:= 2 to n+ 1 do begin x:=a[i]; while (t> 0 ) and (s[t]>=x) do begin r[w[t]]:=i- 1 ; dec(t); end ; inc(t); s[t]:=x;w[t]:=i; end ; //正向单调栈,求出每个元素向右递增最多到哪个位置 t:= 1 ; s[ 1 ]:=a[n];w[ 1 ]:=n; for i:=n- 1 downto 0 do begin x:=a[i]; while (t> 0 ) and (s[t]<=x) do begin l[w[t]]:=i+ 1 ; dec(t); end ; inc(t); s[t]:=x;w[t]:=i; end ; //逆向单调栈,求出每个元素向左递减最多到哪个位置 for i:= 1 to n do begin b:=r[i]; for j:=b downto i do if l[j]<=i then begin len:=j-i; break; end ; if len>ans then ans:=len; b:=l[i]; for j:=b to i do if r[j]>=i then begin len:=i-j; break; end ; if len>ans then ans:=len; end ; { 上面这部分算是比较重点的,从1到n枚举i 对i位置的元素我进行了双向的处理,这里对正向的简单说一下, 用b存i向右递增区间的右端点 (注:b+1位置的元素小于等于i,这就是单调栈的作用) j变量从b再向左枚举, 判断b的向左递减区间的左端点是否小于等于i, 若是,则i~j即是i~b间最长的以i为左端点的美学区间, 可以break一下减少循环量。 逆向的处理道理是相同的。 } if ans<= 0 then writeln (- 1 ) else if ans<=k then writeln (ans) else writeln (ans-k); //判断,输出 end ; begin assign(input, 'baskets.in' ); reset(input); assign(output, 'baskets.out' ); rewrite(output); readln(m); for i:= 1 to m do doing; //对每组数据操作 close(input); close(output); end . |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?