双端队列
Posted hhyx
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了双端队列相关的知识,希望对你有一定的参考价值。
# 题意
n个数进行排序,只能用双端队列,只能进行两个操作
1、新建双端队列,将当前书作为队列中的唯一数
2、将当前数放入已有的队列之前或尾后
最后所有队列按一定顺序连接起来的答案求出最小的队列数
# 题解
直接模拟求解很难,局部决策可能会导致后面有一个数大小位于已经插入的两个数中间,因为只能使用双端队列,所以错误
反向思考问题,把一个A[ 1 , n ]的已经排好顺序的序列,分成尽量少的段,
每一段都是一个双端队列.
单谷性质(先单减,后递增)
开一个数组也就是B数组,记录原数组A的每一个数的下标,然后我们发现如果B的一段满足单单谷性质,那么这一段就可以形成合法的双端序列.
因为单谷性质,前半段可以视为从队头加入,后半段视为从队尾加入.
数值相同的点的下标可以交换用来满足单谷序列
所有值相同的都是一个vector,对于每一个值的下标都从小到大排序
贪心过程:
求单调递减时候,如果上一个点的下标比当前值下标最大的还要大,那么显然将下标最小的点放到最后可以将所有当前值都存入,
否则就证明到达谷底,结束的即为当前最大值,因为接下来就要检查递增,而递增是优先放下标最大的所以如果转到求递增的时候,下标是连续的相同值的下标,显然最优
求递增的时候如果值相同,上一个点的下标比当前的值下标最小的还要小就一定可以一直放,直到最大
贪心求得最少的谷底数,即为最少的单谷段,即答案
时间复杂度O(nlogn)
1 #include<bits/stdc++.h>
2 #define pii pair<int,int>
3 #define pb push_back
4 #define fi first
5 #define se second
6 using namespace std;
7 const int N=2e5+10;
8 pii a[N];
9 vector<int>p[N];
10 int main(){
11 int n;
12 cin>>n;
13 for(int i=0;i<n;i++){
14 cin>>a[i].fi;
15 a[i].se=i;
16 }
17 sort(a,a+n);
18 int tot=0;
19 for(int i=0;i<n;i++){
20 p[++tot].pb(a[i].se);
21 while(a[i+1].fi == a[i].fi)
22 p[tot].pb(a[++i].se);
23 }
24 for(int i=1;i<=tot;i++)
25 sort(p[i].begin(),p[i].end());
26
27 bool flag=0;//记录是否到达转折点
28 int pos=INT_MAX,ans = 1;
29 for(int i=1;i<=tot;i++){
30 int ed=p[i].size()-1;
31 if(flag){//求递增
32 if(pos < p[i][0])
33 pos = p[i][ed];//无法递增移动端点,区间个数+1
34 else{
35 ++ans;
36 pos = p[i][0];
37 flag=0;
38 }
39 }
40 else {//求递减
41 if(pos > p[i][ed])
42 pos = p[i][0];
43 else{
44 flag = 1;
45 pos = p[i][ed];
46 }
47 }
48 }
49 cout<<ans<<endl;
50 }
以上是关于双端队列的主要内容,如果未能解决你的问题,请参考以下文章