題解 P6891 【[JOISC2020]ビルの飾り付け 4】

EternalEpic發表於2024-09-18

如果要看能統計方案數的加強版,可以轉至劃分

這題如果每次暴力從上一個狀態列舉轉移可以得到一個時間複雜度為 \(O(n^2)\) 的樸素動態規劃,期望得分 \(19\) 分。

觀察樸素動態規劃方程,並經過打表可以發現,對於每一個階段,在一個序列中選取點的個數是連續的一段區間。

那麼我們可以考慮少列舉一層狀態(選取個數),把控制區間記錄在陣列裡,這樣就可以 \(O(1)\) 轉移啦。

輸出答案方案,只需要逆序判斷就可。

至於我上文提到的加強版,需要讀者掌握一定的多項式技術,筆者也在自己研究中,可以參考牛客網出題人的題解。

code:

// Program written by Liu Zhaozhou ~~~
#include <bits/stdc++.h>

using namespace std;

inline char gc(void) {
	static char buf[100000], *p1 = buf, *p2 = buf;
	return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, 100000, stdin), p1 == p2) ? EOF : *p1++;
}

template <class T> inline void read(T &x) {
	T f = 1; x = 0; static char c = gc();
	for (; !isdigit(c); c = gc()) if (c == '-') f = -f;
	for (; isdigit(c); c = gc()) x = (x << 1) + (x << 3) + (c & 15);
	x *= f;
}

inline void readstr(string&x) {
	x = ""; static char ch;
	while (isspace(ch = gc()));
	while (x += ch, !isspace(ch = gc()));
}

inline void readstr(char *s) {
	do *s = gc(); while ((*s == ' ') || (*s == '\n') || (*s == '\r'));
	do *(++s) = gc(); while ((~*s) && (*s != ' ') && (*s != '\n') && (*s != '\r'));
	*s = 0; return;
}

inline void readch(char&x) { while (isspace(x = gc())); }

char pf[100000], *o1 = pf, *o2 = pf + 100000;
#define ot(x) (o1 == o2 ? fwrite(pf, 1, 100000, stdout), *(o1 = pf) ++= x : *o1 ++= x)
template <class T>
inline void println(T x, char c = '\n') {
	if (x < 0) ot(45), x = -x;
	static char s[15], *b; b = s;
	if (!x) *b ++= 48;
	for (; x; * b ++= x % 10 + 48, x /= 10);
	for (; b-- != s; ot(*b)); ot(c);
}

template <class T> inline void write(T x) {
	if (x < 0) x = -x, putchar('-');
	if (x > 9) write(x / 10);
	putchar(x % 10 + 48);
}

template <class T> inline void writeln(T x, char c = '\n') { write(x); putchar(c); }
template <class T> inline void chkmax(T &x, const T y) { x > y ? x = x : x = y; }
template <class T> inline void chkmin(T &x, const T y) { x < y ? x = x : x = y; }

inline void file(string str) {
	freopen((str + ".in").c_str(), "r", stdin);
	freopen((str + ".out").c_str(), "w", stdout);
}

#define Ms(arr, opt) memset(arr, opt, sizeof(arr))
#define Mp(x, y) make_pair(x, y)

typedef long long ll;
typedef pair <int, int> pii;

const int INF = 0x3f3f3f3f;

const int Maxn = 5e5 + 5;
int n, a[Maxn * 2], b[Maxn * 2];
pii f[Maxn * 2][2]; char ans[Maxn * 2];
inline void update(pii &x, pii y) {
	chkmin(x.first, y.first);
	chkmax(x.second, y.second);
}

signed main(void) {
	read(n); int m = n * 2;
	for (int i = 1; i <= m; i++) read(a[i]);
	for (int i = 1; i <= m; i++) read(b[i]);
	
	f[0][0] = f[0][1] = Mp(0, 0);
	for (int i = 1; i <= m; i++) {
		f[i][0] = f[i][1] = Mp(INF, -INF);
		if (a[i - 1] <= a[i]) update(f[i][0], f[i - 1][0]);
		if (a[i - 1] <= b[i]) update(f[i][1], f[i - 1][0]);
		if (b[i - 1] <= a[i]) update(f[i][0], f[i - 1][1]);
		if (b[i - 1] <= b[i]) update(f[i][1], f[i - 1][1]);
		++f[i][1].first; ++f[i][1].second;
	}
	
	int cur = -1, rem = n;
	for (int i = 0; i < 2; i++)
		if (f[m][i].first <= n && f[m][i].second >= n) cur = i;
	if (cur == -1) { puts("-1"); return 0; }
	for (int i = m; i >= 1; i--) {
		ans[i] = (cur ? 'B' : 'A'); rem -= cur;
		int opt = (cur ? b[i] : a[i]);
		if (a[i - 1] <= opt && f[i - 1][0].first <= rem && f[i - 1][0].second >= rem) cur = 0;
		else cur = 1;
	} puts(ans + 1);
//	fwrite(pf, 1, o1 - pf, stdout);
	return 0;
}

/**/

相關文章