题意:
将一个序列分成两个序列,两个序列中元素的相对顺序保持和原序列不变,使得分出的两个序列一个严格上升,一个严格下降。
思路:
我们考虑每个元素都要进入其中一个序列。
那么我们维护一个上升序列和一个下降序列,对于当前元素$i$:
如果它只能确定的进入一个序列,那么就让它进入。
如果它一个序列也进不去,那么答案就是'NO'。
如果它两个序列都可以进去,那么判断它和后一个元素(如果存在的话)的关系,如果它后一个元素比它大,那么让它进去上升序列,否则进去下降序列。
考虑这样为什么是对的:
首先我们知道一个存在答案的序列里面的元素重复度最大是$2$,那么对于上述的第三种操作,我们考虑一种最特殊的情况,
就是对于第一个元素的判断,它显然可以进入任意一个序列,但是至于让它进入哪个序列,我们不知道。
但是一个比较直观的感觉是,如果它和剩下的数相比相对来说是较大的,我们倾向于让它进入下降序列,反之,进入上升序列
那么其实不用跟剩下的所有数比,只需要让它和后一个数比一下即可。
因为这一步比较,相当于让这个数强行接在后一个数的前面,可以等价于去掉这个数,(做不了选择就不做选择了嘛
但是后一个数跟它相等怎么办?
相等,就两个序列分别进一个呗。
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 #define N 200010 5 #define INF 0x3f3f3f3f 6 int n, arr[N]; 7 vector <int> A, B; 8 int used[N]; 9 10 void solve() 11 { 12 A.clear(), B.clear(); 13 memset(used, 0, sizeof used); 14 A.push_back(-1); 15 B.push_back(INF); 16 for (int i = 1; i <= n; ++i) 17 { 18 int x = arr[i], a = A.back(), b = B.back(), y; 19 if (x <= a && x >= b) 20 { 21 puts("NO"); 22 return; 23 } 24 else if (x > a && x < b) 25 { 26 if (i == n) 27 used[i] = 1; 28 else 29 { 30 y = arr[i + 1]; 31 if (y > x) 32 A.push_back(x); 33 else 34 { 35 B.push_back(x); 36 used[i] = 1; 37 } 38 } 39 } 40 else if (x > a) 41 A.push_back(x); 42 else 43 { 44 used[i] = 1; 45 B.push_back(x); 46 } 47 } 48 puts("YES"); 49 for (int i = 1; i <= n; ++i) 50 printf("%d%c", used[i], " "[i == n]); 51 } 52 53 int main() 54 { 55 while (scanf("%d", &n) != EOF) 56 { 57 for (int i = 1; i <= n; ++i) scanf("%d", arr + i); 58 solve(); 59 } 60 return 0; 61 }