begin
l[b[q]]:
=i;
dec(q);
end;
inc(q);b[q]:
=i;
end;
fori:
=1tondo
begin
temp:
=(r[i]-l[i]-1)*a[i];
iftemp>ansthenans:
=temp;
end;
writeln(ans);
end.
单调队列及其应用
关键字
队列,合并果子,窗户,广告印刷,最长XX子序列,志愿者选拔,动态规划,烽火传递
正文
单调队列,望文生义,就是指队列中的元素是单调的。
如:
{a1,a2,a3,a4……an}满足a1<=a2<=a3……<=an,a序列便是单调递增序列。
同理递减队列也是存在的。
单调队列的出现可以简化问题,队首元素便是最大(小)值,这样,选取最大(小)值的复杂度便为o
(1),由于队列的性质,每个元素入队一次,出队一次,维护队列的复杂度均摊下来便是o
(1)。
如何维护单调队列呢,以单调递增序列为例:
1、如果队列的长度一定,先判断队首元素是否在规定范围内,如果超范围则增长对首。
2、每次加入元素时和队尾比较,如果当前元素小于队尾且队列非空,则减小尾指针,队尾元素依次出队,直到满足队列的调性为止
要特别注意头指针和尾指针的应用。
下面介绍单调队列的具体应用:
一、单调队列的直接应用
1.合并果子
【问题描述】
在一个果园里,多多已经将所有的果子打了下来,而且按果子的不同种类分成了不同的堆。
多多决定把所有的果子合成一堆。
每一次合并,多多可以把两堆果子合并到一起,消耗的体力等于两堆果子的重量之和。
可以看出,所有的果子经过n-1次合并之后,就只剩下一堆了。
多多在合并果子时总共消耗的体力等于每次合并所耗体力之和。
因为还要花大力气把这些果子搬回家,所以多多在合并果子时要尽可能地节省体力。
假定每个果子重量都为1,并且已知果子的种类数和每种果子的数目,你的任务是设计出合并的次序方案,使多多耗费的体力最少,并输出这个最小的体力耗费值。
例如有3种果子,数目依次为1,2,9。
可以先将 1、2堆合并,新堆数目为3,耗费体力为3。
接着,将新堆与原先的第三堆合并,又得到新的堆,数目为12,耗费体力为 12。
所以多多总共耗费体力=3+12=15。
可以证明15为最小的体力耗费值。
【输入文件】
输入文件fruit.in包括两行,第一行是一个整数n(1<=n<=10000),表示果子的种类数。
第二行包含n个整数,用空格分隔,第i个整数ai(1<=ai<=20000)是第i种果子的数目。
【输出文件】
输出文件fruit.out包括一行,这一行只包含一个整数,也就是最小的体力耗费值。
输入数据保证这个值小于231。
【样例输入】
3
129
【样例输出】
15
【数据规模】
对于30%的数据,保证有n<=1000;
对于50%的数据,保证有n<=5000;
对于全部的数据,保证有n<=10000。
分析:
这个题目非常的经典,发放也很多,可以采用快排或者堆,其思想都是选取当前最小的两个堆进行合并。
复杂度均为O(nlogn),如果用有序队列维护,时间复杂度为O(n)。
每次选取进行合并的两堆,不是最先给定的堆,就是合并最初堆若干次后得到的新堆,所以需要维护两个单调递增队列,一个队列存最初给定的堆的值
(1),一个存合并后得到的新值
(2)。
每次选择时有三种状态:
1、 选取队一的队首两个 2、选取队2的的队首两个 3、选取二者队首各一个
只需对每个队列的指针做相应的更改。
特别注意初始化。
这道题很好的运用了题目中决策的单调性,对初始对经行排序,保证了其单调性。
而对于新产生的堆来说,一旦有新元素加入其中,则新元素一定大于原有元素。
(很显然,由于队列1的单调性)。
也就是说,队列的单调性是自然而然的。
是不需要维护的。
要善于观察分析,才能发现。
Code
programliukee;
var
a,b:
array[1..100000]oflongint;
h1,h2,t2,temp,n,i,ans:
longint;
functionmin(a,b,c:
longint):
longint;
begin
ifa=a
elsemin:
=b;
ifc=c;
end;
proceduresort(l,r:
longint);
var
i,j,mid,temp:
longint;
begin
i:
=l;
j:
=r;
mid:
=a[l+random(r-l)];//随机化排序
repeat
whilea[i] whilea[j]>middodec(j);
ifi<=jthen
begin
temp:
=a[i];
a[i]:
=a[j];
a[j]:
=temp;
inc(i);
dec(j);
end;
untili>j;
ifi