2457: [BeiJing2011]双端队列
很奇妙的转化。
题目要求最后的所有序列也是有序的,所以可以求出最后的序列(即排序后的序列),然后分成许多份,要求每一份都是一个双端序列,求最少分成多少份。
一个结论或者规律:每一个双端队列的数对应原序列的下标都是先下降后增加的(考虑双端序列的构造过程,加入一个数,坐标为a,往后枚举的数要么在序列前,要么加入到后,而且往后的数的下标都比a大,所以是先下降后递增的)
那么就是求排序后的序列,的坐标最少多少先下降后上升的序列。
相同的数可以放到同一个双端序列中,一起考虑。
代码
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long LL; 4 5 inline int read() { 6 int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1; 7 for (;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f; 8 } 9 10 const int N = 200010; 11 12 struct Node{ 13 int x,pos; 14 bool operator < (const Node &A) const { 15 if (x == A.x) return pos < A.pos; 16 return x < A.x; 17 } 18 }a[N]; 19 20 int Mx[N],Mn[N]; 21 22 int main() { 23 int n = read(); 24 for (int i=1; i<=n; ++i) { 25 a[i].x = read(),a[i].pos = i; 26 } 27 sort(a+1,a+n+1); 28 int tot = 0; 29 for (int i=1; i<=n; ++i) { 30 if (a[i].x != a[i-1].x || i==1) { 31 Mx[tot] = a[i-1].pos; 32 Mn[++tot] = a[i].pos; 33 } 34 } 35 Mx[tot] = a[n].pos; 36 37 int flag = 1,H = 0x7fffffff,ans = 0; 38 for (int i=1; i<=tot; ++i) { 39 if (!flag) { // 求下降的过程 40 if (H > Mx[i]) H = Mn[i]; // 下降 41 else H = Mx[i],flag = 1; // 转折,变为上升 42 } 43 else { // 求上升的过程 44 if (H < Mn[i]) H = Mx[i]; // 上升 45 else H = Mn[i],flag = 0,ans++; // 转折,变为下降,表示新增加一个双端序列,ans++ 46 } 47 } 48 cout << ans; 49 return 0; 50 }