【LOJ3271】「JOISC 2020 Day1」建筑装饰 4

题目链接

点击打开链接

题目解法

由题,不难得到一个 O ( N 2 ) O(N^2) 的动态规划解法:记 d p i , 0 / 1 , j dp_{i,0/1,j} 表示是否存在一个长度为 i i 的合法 AB 序列,满足存在 j j 个 A ,且最后一个元素是 / 不是 A ,转移显然。

引理: d p i , 0 / 1 dp_{i,0/1} 中,值为真的部分是一个区间。
证明: 考虑归纳法,对于 N 1 N\leq 1 的情况,引理显然成立。
d p N 1 , 0 / 1 dp_{N-1,0/1} 中存在至少一个数组值为真的部分为空,则引理显然成立;
否则, 即 d p N 1 , 0 / 1 dp_{N-1,0/1} 值为真的部分均非空,有 A N 1 , B N 1 m i n { A N 2 , B N 2 } A_{N-1},B_{N-1}\geq min\{A_{N-2},B_{N-2}\}
讨论 d p N 2 , 0 / 1 dp_{N-2,0/1} 值为真的部分是否为空,可以发现 d p N 1 , 0 / 1 dp_{N-1,0/1} 值为真的部分对应的区间一定存在相交部分,或公共端点,由上述 DP 的转移,可知引理成立。

由此,可以直接维护 d p i , 0 / 1 dp_{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;
}
发布了813 篇原创文章 · 获赞 93 · 访问量 18万+

猜你喜欢

转载自blog.csdn.net/qq_39972971/article/details/105074191