Bzoj2457 双端队列

时间:2021-08-09
本文章向大家介绍Bzoj2457 双端队列,主要包括Bzoj2457 双端队列使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

某一天在晚自习的时候无聊做的思维题。

结果真就做出来了。

Description:

Sherry现在碰到了一个棘手的问题,有N个整数需要排序。
Sherry手头能用的工具就是若干个双端队列。
她需要依次处理这N个数,对于每个数,Sherry能做以下两件事:
1.新建一个双端队列,并将当前数作为这个队列中的唯一的数;
2.将当前数放入已有的队列的头之前或者尾之后。
对所有的数处理完成之后,Sherry将这些队列排序后就可以得到一个非降的序列。

Input
第一行包含一个整数N,表示整数的个数。接下来的N行每行包含一个整数Di,其中Di表示所需处理的整数。
Output
其中只包含一行,为Sherry最少需要的双端队列数。
Sample Input
6 
3 6 0 9 6 3
Sample Output
2
Hint
100%的数据中N≤200000。
Source
Bejing Day1

solution

考虑这道题从何入手,正常想法都是正着取按照要求模拟一下。

但是这道题有些恶心,如果一个双端队列中存在一个相邻的二元组 \((u,v)\)

且在原序列当中 \((u,v)\) 不相邻。那么就有可能出现一个元素 \(o\)

满足 \(pos[o] \in (pos[u],pos[v])\)\(o \in (u,v)\)

\(pos\) 表示元素在原序列的位置)

那么很明显就是无解了。

因为我们要 按顺序 对原序列进行操作。

最要命的是,这道题很容易出现这种情况,随便构造一个数据就行了。

做数学题的时候有个思想叫 “正难则反” 。

所以我们不妨考虑直接把这个序列变成不下降的,然后再倒推回去(显然这个不下降的序列是唯一的(有相同元素也无妨))。

那么问题可以转化为:

把一个不下降的序列划分成连续的 \(k\) 的子段,使得每一个子段都是可以由原序列经过合法操作得来的。
并求 \(k\) 的最小值。

因为题目的要求是按顺序,所以我们离散化一下,排序的时候记录一下这个元素在原序列的位置 \(pos\)

现在考虑一下,怎么样的一个(离散后序列中的)子段才是合法的?

不难得出:对于一个子段,它想要合法,那么它不可能有形如 \(pos={1,7,2}\)
这样子的排列。

因为你不可能把 \(a[1],a[2]\) 插入之后再在它们之间插入一个 \(a[7]\) 啊(\(a[1],a[2]\) 又不能出队)。

说白了就是 \(pos\) 要有单调性,但我们这里是双端队列,两边都能入队(扩展)。

那么分析一下,就有一个性质:

对于一个子段里的 \(pos\) 最小(大)的数,一定满足它两边分别单调。

或者整段单调,甚至可以是就只有他一个元素。

也就是这样子的:

现在随便来一组数据模拟一下:

n=8,a={3,9,4,8,8,9,7,2};

离散之后:

a={2,3,4,7,8,8,9,9}
pos={8,1,3,7,4,5,2,6}

很明显其中一种最优划分是

a : |2 3 4 7|,|8 8 9|,|9|。

pos:|8 1 3 7|,|4 5 2|,|6|。

画一个图:

拆出来就是这样的三段函数:

满足性质。

(实际上就是一个单谷性质)

那么我们离散之后统计一下 \(pos\) 的单调性然后随便贪一贪,分一下就可以了。

原文地址:https://www.cnblogs.com/BTeqwq/p/bzoj2457.html