双端队列排序--解题报告

it2022-05-05  206

双端队列排序

discription

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

100%的数据中N≤200000。

解题思路

1.这道题虽然叫做双端队列,但是如果要使用deque(双端队列)来解的话那么只会gg,重要的是理解deque的特性只能在对头或队尾进行增删。 2.观察这道题的数据规模,发现是两万,如果算法是O(n^2)的话那么就直接gg了,如果是O(n logn),在每一次操作的比较多的话,那么也会超时,所以得用O(n)的算法qwq。 3.如何在只扫描一遍的情况下ac这道题,首先我们要排除掉模拟的方法,因为模拟的话铁定超时,那么怎么办?寻求一个单个双端队列的本质:1.它是一个单调的队列,是升序(非降序);2.所有队列合起来,会得到一个更大的单调队列。这很像一个排序的思想,而将多个有序队列合并成一个更大的有序队列,这不正是大名鼎鼎的合并排序了吗? 4.现在问题已经被简化了,我们只需要求出这次的合并排序中,最少会被分成多少个有序的小组就对了。(注意:小组之间有时是可以合并的,例如[1,2,3],可以和[5,4,3]合并为[1,2,3,3,4,5]) 5.如何在常数时间内解决这道题呢?我们可以先得到已经排好序的有序队列,然后再与这个序列进行对比。

最开始的时候数列是 3 6 0 9 6 3 我们最后会得到的序列是 9 6 6 3 3 0 去掉重复的值 9 6 3 0 发现9和6在一起,6和3在一起,3和0在一起 拆分我们现在的序列 [3 6] [0 9] [6 3]; 合并 -> [3 6 9] [0 3 6]

神奇的事情发生了,我们居然得到了样例的答案!

但是这还没完,时间复杂度,还不够,离答案只剩一点点了!

这样虽然大大简化了难度和时间复杂度(相对于模拟),但是仍不足以支持我们ac,因为得到临近顺序之后再一个个比较的工作量是巨大的,有没有什么办法可以让这个队列的合并从一开始就决定了?亦或是根本就不知道它怎么合并就可以得到答案?蒟蒻的我想不出后者,所以只能绞尽脑汁在前者上面做功夫。 ---------- 由于排序的是数字的值,我们可以反过来想,我们要干的事就是要在这个值里面找到可以相呼应的区间,那么在排序的时候就得存下它的下标(序号)num,在重新扫描已经排好的序列的时候,就可以直接找扫描序列中下标的‘拐点’,也就是单调性发生改变的点。因为数组下标(num)代表的是这个数在序列中的位置,并且我们扫描的是已经排好的序列,那么在同一个单调的序列中,下标单调性改变的话就必然排不起来那么就需要另一个队列。 题目说道这里已经很清楚了,下面直接上代码~~!

#include<iostream> #include<cstdio> #include<algorithm> using namespace std; const int maxn=2e5+10; const int inf = 2e9; int ans = 1; int f = 1,noww=inf; struct node { int tail, p; } s[maxn]; bool cmp(node x, node y) { if (x.tail == y.tail) return x.p < y.p; return x.tail < y.tail; } int main() { int n; cin>>n; for (int i = 1; i <= n; i++) { scanf("%d", &s[i].tail); s[i].p = i; } sort(s + 1, s + n + 1, cmp); for (int i = 1; i <= n; ) { int j = i; while (s[j + 1].tail == s[j].tail && j < n) j++; if (f == 1) { if(s[j].p<noww) noww=s[i].p; else { f=0; noww=s[j].p; } } else { if(s[i].p>noww) noww=s[j].p; else { f=1; ans++; noww=s[i].p; } } i = j+1; } cout<<ans; return 0; }

最新回复(0)