Solution
一道不错的题目。首先套路明显是逐位贪心。那么现在问题变成了如何判断一种方案是否可行。
定义原前缀最大值为在p中的前缀最大值。考虑这个题目的几个最重要的性质:
- 原前缀最大值一定任然是前缀最大值。
- 非原前缀最大值之所以能够成为新的前缀最大值,一定是因为他的“克星”在另一个序列中,也就是说,如果将这个数换到另一个序列中,那么他将不会成为前缀最大值。
那么所以,我们可以得到一些推论:
- 如果存在解,那么可以使得最后某一个序列中的前缀最大值都是原前缀最大值。原因很简单,因为如果两个序列中都有非原前缀最大值,那么根据性质2,可以交换这两个值所在的序列,这两个值就都变成非前缀最大值,并且两边前缀最大值的数量两边同时减一,任然合法。那么不妨设这个都是原前缀最大值的序列为AAA,反之为BBB。
- 任意取一个上升子序列作为BBB之后的前缀最大值序列(只要满足这个上升子序列的第一项≥B\geq B≥B当前的前缀最大值),都是合法的。原因是BBB先取这些选的数,然后对于剩下的数,我们根据性质2可知它在某一个序列中一定不是前缀最大值,这样就可以控制不是硬点的前缀最大值的值变成一个新的前缀最大。
现在考虑如果现在AAA的前缀最大值个数为l1l_1l1,BBB的为l2l_2l2。设之后的原前缀最大值有QQQ个,其中BBB用了kkk个,同时新增了mmm个。那么有:l1+Q−k=k+m+l2l_1 + Q - k = k + m + l_2l1+Q−k=k+m+l2
即l1−l2+Q=2k+ml_1 - l_2 + Q = 2k + ml1−l2+Q=2k+m
意义就是考虑对于原前缀最大值,其权值为222,反之为111,问是否存在一个上升子序列满足其权值等于l1−l2+Ql_1-l_2+Ql1−l2+Q,设这个数为LLL。
首先,如果子序列最大值都≤L\leq L≤L,那么一定不行。
反之,如果子序列的最大值为奇数,那么一定是可以的。原因是由于最大值是奇数,那么其中一定至少有一个非原前缀最大值,即最大值是如下构成的:2,2,2,2...,12,2,2,2...,12,2,2,2...,1,从而可以构成不大于最大值的任何非负整数。(可以每次减二,减到不能减为止,如果LLL为偶数,就再减去一个111)。
如果最大值为偶数,由于不一定有111,所以不一定所有数都能构成。这种情况发生在LLL是奇数下,但是我们发现如果可行,那么权值为奇数的子序列的最大值一定≥L\geq L≥L。
综上,实际上只需要判断与LLL同奇偶权值的子序列的权值最大值即可。
Code
#include <bits/stdc++.h>
#define mp make_pair
#define pb push_back
#define ph push
#define ptc putchar
#define enter putchar('\n')
#define mod 998244353
using namespace std;
typedef pair<int,int> pii;
typedef double db;
typedef long double ldb;
typedef long long ll;
typedef long long lnt;
inline int read(){
int x = 0;char c = getchar();
while (!isdigit(c)) c = getchar();
while (isdigit(c)) x = (x << 1) + (x << 3) + c - '0' , c = getchar();
return x;
}
inline void write(int x){
if (!x){
ptc('0');
return;
}
int dg[20] , len = 0;
while (x) dg[len++] = x % 10 , x /= 10;
while (len--) ptc(dg[len]+'0');
}
inline void writeln(int x){
write(x);
ptc('\n');
}
inline int add(int x,int y){
x += y;if (x >= mod) x -= mod;
return x;
}
inline int sub(int x,int y){
x -= y;if (x < 0) x += mod;
return x;
}
inline int qpow(int x,int y){
int res = 1;
while (y){
if (y & 1) res = 1ll * res * x % mod;
x = 1ll * x * x % mod;y >>= 1;
}
return res;
}
const int N = 2e5 + 10;
int n , a[N] , premax[N] , sufsumpremaxcnt[N];
struct Node{
int maxn , ls , rs;
}tr[N * 50];
int tcnt;
struct Segment_Tree{
int rt[N];
void up(int x){
if (!tr[x].ls) tr[x].maxn = tr[tr[x].rs].maxn;else
if (!tr[x].rs) tr[x].maxn = tr[tr[x].ls].maxn;else
tr[x].maxn = max(tr[tr[x].ls].maxn , tr[tr[x].rs].maxn);
}
void insert(int &x,int prex,int l,int r,int pos,int v){
x = ++tcnt;
if (l == r){
tr[x].maxn = v;
return;
}
int mid = l + r >> 1;
if (pos <= mid) {
tr[x].rs = tr[prex].rs;
insert(tr[x].ls , tr[prex].ls , l , mid , pos , v);
}else{
tr[x].ls = tr[prex].ls;
insert(tr[x].rs , tr[prex].rs , mid + 1 , r , pos , v);
}
up(x);
}
int query(int x,int l,int r,int ql,int qr){
if (!x || ql > qr) return 0;
if (ql <= l && r <= qr) return tr[x].maxn;
int mid = l + r >> 1 , res = 0;
if (ql <= mid) res = max(res , query(tr[x].ls , l , mid , ql , qr));
if (mid < qr ) res = max(res , query(tr[x].rs , mid + 1 , r , ql , qr));
return res;
}
}T[2];
int s[2][N] , maxn[2][N] , len[2] , sum[2];
int res[N];
int check(int id,int pos){//[pos , n]
int need = sum[id] - sum[id ^ 1] + sufsumpremaxcnt[pos];
if (need < 0) return 0;
int most = T[need & 1].query(T[need & 1].rt[pos] , 1 , n , maxn[id ^ 1][len[id ^ 1]] + 1 , n);
return most >= need;
}
int main(){
scanf("%d",&n);
for (int i = 1;i <= n;i++){
scanf("%d",a + i);
premax[i] = max(premax[i-1] , a[i]);
}
for (int i = n;i >= 1;i--){
sufsumpremaxcnt[i] = sufsumpremaxcnt[i + 1] + (premax[i] == a[i]);
}
for (int i = n;i >= 1;i--){
int d0max = T[0].query(T[0].rt[i+1] , 1 , n , a[i] + 1 , n) , d1max = T[1].query(T[1].rt[i+1] , 1 , n , a[i] + 1 , n);
if (premax[i] == a[i]){
T[0].insert(T[0].rt[i] , T[0].rt[i+1] , 1 , n , a[i] , d0max + 2);
if (d1max) T[1].insert(T[1].rt[i] , T[1].rt[i + 1] , 1 , n , a[i] , d1max + 2);else T[1].rt[i] = T[1].rt[i + 1];
}else{
T[1].insert(T[1].rt[i] , T[1].rt[i+1] , 1 , n , a[i] , d0max + 1);
if (d1max) T[0].insert(T[0].rt[i] , T[0].rt[i+1] , 1 , n , a[i] , d1max + 1);else T[0].rt[i] = T[0].rt[i + 1];
}
}
memset(res , -1 , sizeof res);
for (int i = 1;i <= n;i++){
for (int d = 0;d < 2;d++){
s[d][++len[d]] = a[i];
maxn[d][len[d]] = max(maxn[d][len[d] - 1] , a[i]);
sum[d] += maxn[d][len[d]] == s[d][len[d]];
if (check(0 , i + 1)) {res[i] = d;break;}
if (check(1 , i + 1)) {res[i] = d;break;}
sum[d] -= maxn[d][len[d]] == s[d][len[d]];
--len[d];
}
if (res[i] == -1) return puts("-1") , 0;
}
for (int i = 1;i <= n;i++) printf("%d",res[i]);
return 0;
}