题意:给出一个序列,要求把这个序列分成两个序列,要求这两个序列的前缀极大值的个数相同,给出字典序最小的构造。
做法:
首先肯定是逐位确定,那么假设第一个序列目前有 \(a\) 个最大值,第二个序列有 \(b\)。注意到原序列的前缀极大值分到两个序列中肯定还是前缀极大值,我们研究这个前缀极大值的一些性质。
经过一些手玩可以发现,对于这两个序列剩余的部分中,一定存在一个解满足其中一个序列中的极大值完全由原序列的极大值构成。
考虑如何证明,如果两个序列中都存在不在原序列中的极大值,那么我们令他们交换,在第一个序列中的改成在第二序列中,第二序列中的改在第一序列中,发现他们会同时被消掉,所以可以满足。
那么我们不妨假设第一个序列极大值完全由原序列组成,我们发现,如果我们确定了第二个序列中哪些数由极大值构成,那么我们就直接确定了第一个序列,同时也需要满足我下一个数要比目前第二个序列的极大值要大。
假设我剩下 \(k\) 个极大值,\(t\) 个被第二个序列用掉,第二个序列剩下包括原序列极大值的极大值个数为 \(l\),那么要求 \(a+k-t=l+b,a+k-b=t+l = 2t+(l-t)\)。考虑右侧的意义,我们令原序列中极大值权为 \(2\),剩余的为 \(1\),那么我们就等于能找到一个上升子序列的权等于 \(a+k-b\)。
判定很难做,但是我们注意到我们可以无代价地将一个原序列极大值塞进第一个序列,塞完之后也可以塞剩余的 \(l-t\),所以发现我们其实只需要对于 \(l-t \bmod 2=1\) 和 \(l-t \bmod 2=0\) 两种情况分别统计最大值即可,直接用线段树维护带权 lis 最大值即可。
代码:
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int maxn = 2e5 + 5, inf = 2e9;
struct node {int v[2];friend node operator+(node x, node y) {return node{max(x.v[0], y.v[0]), max(x.v[1], y.v[1])};}node() {v[0] = v[1] = -inf;}node(int V0, int V1) {v[0] = V0, v[1] = V1;}
} ;
struct Segtree {node tr[maxn << 2];void pushup(int t) {tr[t] = tr[t << 1] + tr[t << 1 | 1];}void modify(int l, int r, int pos, int t, node val) {if(l == r) {tr[t] = val;return ;}int mid = l + r >> 1;if(pos <= mid)modify(l, mid, pos, t << 1, val);elsemodify(mid + 1, r, pos, t << 1 | 1, val);pushup(t);}node query(int l, int r, int x, int y, int t) {if(x > y)return node();if(x <= l && r <= y)return tr[t];int mid = l + r >> 1;if(y <= mid)return query(l, mid, x, y, t << 1);if(mid < x)return query(mid + 1, r, x, y, t << 1 | 1);return query(l, mid, x, y, t << 1) + query(mid + 1, r, x, y, t << 1 | 1);}
} tree;
node res[maxn];
int n, p[maxn], use[maxn], mx, r;
string s;
bool chk(int v, int x) {if(x < 0)return 0;node t = tree.query(1, n + 1, v + 1, n + 1, 1);
// cout << x << " " << v << "Adsfdsaf" << " " << t.v[x % 2] << endl;return t.v[x % 2] >= x;
}
signed main() {cin >> n;for (int i = 1; i <= n; i++) {cin >> p[i];if(p[i] > mx) {mx = p[i];use[i] = 1;r++;}}tree.modify(1, n + 1, n + 1, 1, node(0, -inf - 1));for (int i = n; i >= 1; i--) {node t = tree.query(1, n + 1, p[i] + 1, n + 1, 1);res[i].v[0] = t.v[1 ^ use[i]] + use[i] + 1,res[i].v[1] = t.v[0 ^ use[i]] + use[i] + 1;tree.modify(1, n + 1, p[i], 1, res[i]);// cout << res[i].v[0] << " " << res[i].v[1] << endl;}int nwx = 0, nwy = 0, edx = 0, edy = 0;for (int i = 1; i <= n; i++) {r -= use[i];tree.modify(1, n + 1, p[i], 1, node());int tox = nwx + (p[i] > edx);// cout << edx << "asdf " << nwy - tox + r << endl;if(chk(edy, tox - nwy + r) || chk(edx, nwy - tox + r)) {s += '0';nwx = tox;edx = max(edx, p[i]);}else {s += '1';nwy += (p[i] > edy);edy = max(edy, p[i]);}// cout << nwx << " " << nwy << endl;}if(nwx != nwy)cout << -1 << endl;elsecout << s << endl;return 0;
}