題目傳送門
【題目大意】
用若干個雙端佇列給$n$個整數排序,依次處理這$n$個數,對於每個數$a_i$,可以進行兩種操作:
1.新建乙個雙端佇列,並將$a_i$作為這個佇列中唯一的數
2.把$a_i$從已有佇列的隊頭或隊尾入隊
對所有的數處理完後,要求這些佇列能夠按照一定的順序連線起來,得到乙個非降的長度為$n$的序列,求最少需要多少個雙端佇列。
【思路分析】
我們把問題反過來思考,先把$n$個數從小到大排序,然後分成盡量少的幾段,對應原問題中的合法雙端佇列。
易知乙個結論,對於排序後每個位置的數原本的下標組成的序列$b$,如果一段滿足單谷性質(即先遞減後遞增),那麼這一段就對應原問題中的乙個合法雙端佇列。(遞減的一段相當於從隊頭插入,遞增的一段相當於從隊尾插入)
還要注意一點,就是如果存在相同的幾個數,那麼它們排序後的位置是隨機的,可以看成乙個整體來處理。如果這個整體中最小的下標大於前面的序列中最大的下標,那麼滿足遞增;如果這個整體中最大的下標小於前面的序列中最小的下標,那麼滿足遞減。
【**實現】
1 #include2 #include3 #include4 #include5 #include6**戳這裡#define g() getchar()
7#define rg register
8#define go(i,a,b) for(rg int i=a;i<=b;i++)
9#define back(i,a,b) for(rg int i=a;i>=b;i--)
10#define db double
11#define ll long long
12#define il inline
13#define pf printf
14using
namespace
std;
15int
fr()
22while(ch>='
0'&&ch<='
9') w=(w<<1)+(w<<3)+ch-'
0',ch=g();
23return w*q;24}
25const
int n=200002;26
intn;
27struct
numberd[n];
30struct
linel[n];
33 il bool
cmp(number x,number y)
36int
main()50}
51bool now=0;rg int ans=1
;52 go(i,2
,num)
57else61}
62 pf("
%d\n
",ans);
63return0;
64 }
雙端佇列 Acwing 134 雙端佇列
達達現在碰到了乙個棘手的問題,有n個整數需要排序。達達手頭能用的工具就是若干個雙端佇列。她從1到n需要依次處理這n個數,對於每個數,達達能做以下兩件事 1 新建乙個雙端佇列,並將當前數作為這個佇列中的唯一的數 2 將當前數放入已有的佇列的頭之前或者尾之後。對所有的數處理完成之後,達達將這些佇列按一定...
AcWing 134 雙端佇列
題目描述 達達現在碰到了乙個棘手的問題,有n個整數需要排序。達達手頭能用的工具就是若干個雙端佇列。她從1到n需要依次處理這n個數,對於每個數,達達能做以下兩件事 1 新建乙個雙端佇列,並將當前數作為這個佇列中的唯一的數 2 將當前數放入已有的佇列的頭之前或者尾之後。對所有的數處理完成之後,達達將這些...
acwing 134 雙端佇列
把乙個陣列排序,必須使用雙端佇列,必須從1到n依次處理,問最少要多少個雙端佇列。和歸併一樣,在乙個佇列裡,按照陣列下標從1到n,把值大的往後扔,小的往前扔。這樣乙個佇列裡面,從前往後,下標肯定是先減後增的。並且 這些佇列也是有序的,也就是說,除了第乙個佇列,乙個佇列的最小值應該是比乙個佇列的最大值大...