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,
这里我用的是解法一。
具体的见代码中的简析。
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.
浙公网安备 33010602011771号