洛谷 P8277 [USACO22OPEN] Up Down Subsequence P 题解

注:没有dp转移方程的证明。

记录第一道场切的紫题!虽然好像一车人切了

我们设 \(f_i\) 表示如果只考虑前 \(i\) 头奶牛并选择第 \(i\) 头奶牛时的答案。

假设字符串第 \(i\) 位为 \(s[i]\),有转移方程:

\(f_i = \max_{1\leq j\leq i-1} f_j + 1\).

转移的条件是 (\(s_{f_j}=U\) && \(p_i>p_j\) ) || ((\(s_{f_j}=D\) && \(p_i<p_j\) ).

而答案即为 \(max_{1\leq i \leq n} f_i\).

这个 \(\operatorname{dp}\) 显然是 \(O(n^2)\) 的,考虑优化。

我们发现求 \(f_i\) 只需要求一些 \(f_j\) 的最大值,所以我们可以用线段树(树状数组也行,但是我不会)进行优化,具体如下。

建两棵线段树,一个存 \(s_{f_i}=U\) 的,另一个存 \(s_{f_i}=D\)\(f_i\) 值,每次求完一个 \(f_i\) ,就把它放到线段树里,之后转移时即可使用。而初始的时候线段树上所有点的值均为 \(0\),通过后期更改即可。时间复杂度 \(O(n \log n)\)

code:

#include <bits/stdc++.h>

using namespace std;

#define int long long

int n, h[300005], f[300005], ans;
string s;

struct node {
	int l, r, dat;
}t[300005 * 4][2];
void buld(int x, int l, int r, int s) {
	t[x][s].l = l; t[x][s].r = r;
	if (l == r) {t[x][s].dat = 0; return ;}
	int mid = (l + r) / 2;
	buld(x * 2, l, mid, s); buld(x * 2 + 1, mid + 1, r, s);
	t[x][s].dat = max(t[x * 2][s].dat, t[x * 2 + 1][s].dat);
}
void chang(int x, int q, int v, int s) {
	if (t[x][s].l == t[x][s].r) {t[x][s].dat = v; return ;}
	int mid = (t[x][s].l + t[x][s].r) / 2;
	if (q <= mid) chang(x * 2, q, v, s);
	else chang(x * 2 + 1, q, v, s);
	t[x][s].dat = max(t[x * 2][s].dat, t[x * 2 + 1][s].dat);
}
int ask(int x, int l, int r, int s) {
	if (l <= t[x][s].l && t[x][s].r <= r) return t[x][s].dat;
	int mid = (t[x][s].l + t[x][s].r) / 2;
	int res = -2147483647;
	if (l <= mid) res = max(res, ask(x * 2, l, r, s));
	if (r > mid) res = max(res, ask(x * 2 + 1, l, r, s));
	return res;
}

signed main() {
	cin >> n;
	for (int i = 1; i <= n; i++) cin >> h[i];
	cin >> s;
	buld(1, 1, n, 0); buld(1, 1, n, 1);
	for (int i = 2; i <= n; i++) {
//		for (int j = 1; j < i; j++) {
//			if (s[f[j]] == 'U' && h[i] > h[j]) f[i] = max(f[i], f[j] + 1);
//			if (s[f[j]] == 'D' && h[i] < h[j]) f[i] = max(f[i], f[j] + 1); 
//		}注释的这段为不用线段树优化的dp
		f[i] = max(f[i], ask(1, 1, h[i] - 1, 0) + 1);
		f[i] = max(f[i], ask(1, h[i] + 1, n, 1) + 1);
		//////add 
		if (s[f[i]] == 'U') chang(1, h[i], f[i], 0);
		else chang(1, h[i], f[i], 1);
		ans = max(ans, f[i]);
	}
	cout << ans << endl;
	return 0;
}
posted @ 2025-07-07 21:00  wwqwq  阅读(33)  评论(0)    收藏  举报