【LOJ3271】「JOISC 2020 Day1」建築裝飾 4

題目鏈接

點擊打開鏈接

題目解法

由題,不難得到一個 O(N2)O(N^2) 的動態規劃解法:記 dpi,0/1,jdp_{i,0/1,j} 表示是否存在一個長度爲 ii 的合法 AB 序列,滿足存在 jj 個 A ,且最後一個元素是 / 不是 A ,轉移顯然。

引理: dpi,0/1dp_{i,0/1} 中,值爲真的部分是一個區間。
證明: 考慮歸納法,對於 N1N\leq 1 的情況,引理顯然成立。
dpN1,0/1dp_{N-1,0/1} 中存在至少一個數組值爲真的部分爲空,則引理顯然成立;
否則, 即 dpN1,0/1dp_{N-1,0/1} 值爲真的部分均非空,有 AN1,BN1min{AN2,BN2}A_{N-1},B_{N-1}\geq min\{A_{N-2},B_{N-2}\}
討論 dpN2,0/1dp_{N-2,0/1} 值爲真的部分是否爲空,可以發現 dpN1,0/1dp_{N-1,0/1} 值爲真的部分對應的區間一定存在相交部分,或公共端點,由上述 DP 的轉移,可知引理成立。

由此,可以直接維護 dpi,0/1dp_{i,0/1} 值爲真的區間,省去 DP 的一維。

時間複雜度 O(N)O(N)

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 1e6 + 5;
typedef long long ll;
template <typename T> void chkmax(T &x, T y) {x = max(x, y); }
template <typename T> void chkmin(T &x, T y) {x = min(x, y); } 
template <typename T> void read(T &x) {
	x = 0; int f = 1;
	char c = getchar();
	for (; !isdigit(c); c = getchar()) if (c == '-') f = -f;
	for (; isdigit(c); c = getchar()) x = x * 10 + c - '0';
	x *= f;
}
char ans[MAXN];
int n, a[MAXN], b[MAXN];
pair <int, int> dp[MAXN][2];
void work(int pos, bool type, int lft) {
	if (pos == 0) return;
	ans[pos] = type + 'A', lft -= !type;
	if (!type) {
		if (a[pos] >= a[pos - 1] && dp[pos - 1][0].first <= lft && dp[pos - 1][0].second >= lft) work(pos - 1, 0, lft);
		else work(pos - 1, 1, lft);
	} else {
		if (b[pos] >= a[pos - 1] && dp[pos - 1][0].first <= lft && dp[pos - 1][0].second >= lft) work(pos - 1, 0, lft);
		else work(pos - 1, 1, lft);
	}
}
void update(pair <int, int> &a, pair <int, int> b, bool type) {
	if (type && b.first == n) return;
	if (type) {
		b.first++, b.second++;
		chkmin(b.second, n);
	}
	chkmin(a.first, b.first);
	chkmax(a.second, b.second);
}
int main() {
	read(n);
	for (int i = 1; i <= n * 2; i++)
		read(a[i]);
	for (int i = 1; i <= n * 2; i++)
		read(b[i]);
	for (int i = 0; i <= n * 2; i++)
		dp[i][0] = dp[i][1] = make_pair(n, -n);
	dp[0][0] = make_pair(0, 0);
	for (int i = 1; i <= n * 2; i++) {
		if (a[i] >= a[i - 1] && dp[i - 1][0] != make_pair(n, -n)) update(dp[i][0], dp[i - 1][0], 1);
		if (a[i] >= b[i - 1] && dp[i - 1][1] != make_pair(n, -n)) update(dp[i][0], dp[i - 1][1], 1);
		if (b[i] >= a[i - 1] && dp[i - 1][0] != make_pair(n, -n)) update(dp[i][1], dp[i - 1][0], 0);
		if (b[i] >= b[i - 1] && dp[i - 1][1] != make_pair(n, -n)) update(dp[i][1], dp[i - 1][1], 0);
	}
	if (dp[n * 2][0].second != n && dp[n * 2][1].second != n) {
		puts("-1");
		return 0;
	}
	if (dp[n * 2][0].second == n) work(n * 2, 0, n);
	else work(n * 2, 1, n);
	printf("%s\n", ans + 1);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章