双端队列题解

it2022-05-05  110

Description

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

Input

第一行包含一个整数N,表示整数的个数。接下来的1行包含N个整数Di,其中Di表示所需处理的整数。

Output

其中只包含一行,为Sherry最少需要的双端队列数。

Sample Input

6 3 6 0 9 6 3

Sample Output

2

Hint

N≤200000

分析

若将输入数组a b为a将a排序后的数组 因为将队列排序后能得到单调序列,所以每一个队列为排序后都为排序后数组中连续一段 所以现在问题转化为求b中满足条件的最少划分段数

现在我们再来看怎样的划分是满足条件的 假设其中一个合法的为a[i],a[i+1]…a[j-1],a[j] 不难发现最终队列下标情况为i最小且i两边单调且单调性不同 大概是这样 就这样就行了

标程

#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #define SIZE 200005 using namespace std; struct kkk { int v,num; bool operator < (const kkk &other) const { if(v != other.v) return v < other.v; else return num < other.num; } }a[SIZE]; int maxa[SIZE],mina[SIZE]; int main() { freopen("deque.in","r",stdin); freopen("deque.out","w",stdout); memset(maxa,0xaf,sizeof(maxa)); memset(mina,0x7f,sizeof(mina)); int n; scanf("%d",&n); for(int i = 0;i < n;i++) scanf("%d",&a[i].v),a[i].num = i; sort(a,a+n); int nowa = a[0].v,nowk = 0; int tot = 0; for(int i = 0;i < n;i++) { if(a[i].v == nowa) a[i].v = nowk; else { nowa = a[i].v; nowk++; a[i].v = nowk; } } for(int i = 0;i < n;i++) { maxa[a[i].v] = max(maxa[a[i].v],a[i].num); mina[a[i].v] = min(mina[a[i].v],a[i].num); } if(nowk == 0) { cout<<1; return 0; } bool flag = true; int tot1 = 1,tot2 = 0; for(int i = 1;i <= nowk;i++) { if(flag) { if(mina[i] < maxa[i-1]) flag = false; } else { if(maxa[i] > mina[i-1]) { flag = true; tot1++; } } } if(!flag) tot1++; flag = false; for(int i = 1;i <= nowk;i++) { if(flag) { if(mina[i] < maxa[i-1]) flag = false; } else { if(maxa[i] > mina[i-1]) { flag = true; tot2++; } } } if(!flag) tot2++; cout<<min(tot2,tot1); }

最新回复(0)