AGC028E

题意

\(n\) 和排列 \(a_1,\ a_2,\ ...,\ a_n\)。令 \(b_1,\ b_2,\ ...,\ b_n,\ b_i\ \in\ \{0,\ 1\},\ c\ =\ \{\ a_i\ |\ b_i\ =\ 0\},\ d\ =\ \{\ a_i\ |\ b_i\ =\ 1\}\),其中 \(c\)\(d\) 数字顺序与 \(a\) 中顺序相同。称 \(b\) 是好的当且仅当 \(c\)\(d\) 的前缀最大值个数相同。
问字典序最小的好的 \(b\)。若不存在输出 \(-1\)

\(1\ \leq\ n\ \leq\ 10^5\)

做法1

由于字典序最小,考虑逐位确定。设当前已经填好了 \(i\) 位,\(c\) 的最大值为 \(max_0\)\(c\) 的前缀最大值个数为 \(cnt_0\)\(d\) 的最大值为 \(max_1\)\(d\) 的前缀最大值个数为 \(cnt_1\)。则当前填的合法当且仅当存在如下数列 \(p\)\(q\)

  1. \(max_0\ <\ p_1\ <\ p_2\ <\ ...\ <\ p_k\)
  2. \(max_1\ <\ q_1\ <\ q_2\ <\ ...\ <\ q_m\)
  3. \(cnt_0\ +\ k\ =\ cnt_1\ +\ m\)
  4. \(a\) 中前缀最大值在 \(i\) 之后的出现在 \(p\)\(q\) 中。

现若 \(p\)\(q\) 中均出现 \(a\) 中非前缀最大值的数,则删去这两个数对合法性无影响。所以可以枚举哪一个序列只能由 \(a\) 中的前缀最大值构成,然后判断。可以发现 \(k\ -\ m\) 的取值为 \([l_0,\ r_0]\) 中的偶数和 \([l_1,\ r_1]\) 中的奇数,\(r_0,\ r_1\) 值会在另一个序列取了 \(lis\) 时取到。
时间复杂度 \(O(n\ log\ n)\)

代码

#include <bits/stdc++.h>

#ifdef __WIN32
#define LLFORMAT "I64"
#else
#define LLFORMAT "ll"
#endif

using namespace std;

struct segment_tree {
	segment_tree() {}
	segment_tree(int _n) {
		n = _n;
		N = 1; while(N - 1 <= n) N <<= 1;
		a = vector<int>(N << 1, 0);
	}

	void M(int i, int x) {
		a[i |= N] = x;
		for (i >>= 1; i; i >>= 1) a[i] = max(a[i << 1], a[(i << 1) | 1]);
		return;
	}

	int Q(int i) {
		int x = 0;
		for (int s = (i | N) - 1, t = (n | N) + 1; s ^ t ^ 1; s >>= 1, t >>= 1) {
			if(~s & 1) x = max(x, a[s ^ 1]);
			if(t & 1) x = max(x, a[t ^ 1]);
		}
		return x;
	}
	private :
	vector<int> a;
	int n, N;
};

int main() {
	ios::sync_with_stdio(false);
	int n; cin >> n;
	vector<int> a(n), s(n, 0);
	vector<bool> h(n);
	for (int mx = 0, i = 0; i < n; ++i) cin >> a[i], h[i] = (a[i] > mx), mx = max(mx, a[i]);
	for (int i = n - 1; i; --i) s[i - 1] = s[i] + h[i];

	array<segment_tree, 2> seg = {segment_tree(n), segment_tree(n)};
	for (int i = n - 1; ~i; --i) {
		array<int, 2> g = {seg[0].Q(a[i]), seg[1].Q(a[i])};
		if(h[i]) {
			seg[0].M(a[i], g[0] + 2);
			if(g[1] & 1) seg[1].M(a[i], g[1] + 2);
		}
		else {
			seg[1].M(a[i], g[0] + 1);
			if(g[1] & 1) seg[0].M(a[i], g[1] + 1);
		}
	}

	int max0(0), max1(0), cnt0(0), cnt1(0);
	string ans("");
	for (int x, i = 0; i < n; ++i) {
		x = a[i];
		seg[0].M(x, 0); seg[1].M(x, 0);

		auto check = [&](int max0, int cnt0, int max1, int cnt1) {
			static array<int, 2> g;
			g = {seg[0].Q(max0), seg[1].Q(max0)};
			if(cnt0 + cnt1 + s[i] & 1) {
				if(g[1] & 1) {
					if(cnt0 + 1 <= cnt1 + s[i] && cnt0 + g[1] >= cnt1 + s[i]) return true;
				}
			}
			else {
				if(cnt0 <= cnt1 + s[i] && cnt0 + g[0] >= cnt1 + s[i]) return true;
			}
			g = {seg[0].Q(max1), seg[1].Q(max1)};
			if(cnt0 + cnt1 + s[i] & 1) {
				if(g[1] & 1) {
					if(cnt1 + 1 <= cnt0 + s[i] && cnt1 + g[1] >= cnt0 + s[i]) return true;
				}
			}
			else {
				if(cnt1 <= cnt0 + s[i] && cnt1 + g[0] >= cnt0 + s[i]) return true;
			}
			return false;
		};

		if(check(max(max0, x), cnt0 + (x > max0), max1, cnt1)) { ans += "0"; max0 = max(max0, x); cnt0 += (x == max0); }
		else { ans += "1"; max1 = max(max1, x); cnt1 += (x == max1); }
	}
	if(cnt0 == cnt1) cout << ans << endl;
	else cout << "-1\n";
	return 0;
}
posted @ 2018-10-16 10:09  King_George  阅读(562)  评论(0编辑  收藏  举报