【题解】P11187 配对序列

P11187 配对序列

小学生都会做的小清新递推题。

我们不妨定义:

  • 一个“完整配对子序列”为题目所述的配对子序列
  • 一个“不完整配对子序列”为题目所述配对子序列去掉末尾的数

可以发现:

  • 一个“完整配对子序列”加上一个不等于其末尾的数就是一个“不完整配对子序列”。

  • 一个“不完整配对子序列”加上一个等于其末尾的数就是一个“完整配对子序列”。

考虑维护在 11ii 中以 xx 为结尾的最长“完整配对子序列”和“不完整配对子序列”的长度。

  • 对于“完整配对子序列”,直接用 1i11 \sim {i-1} 中的以 xx 为结尾的“不完整配对子序列”的长度加一更新即可。
  • 对于“不完整配对子序列”,需要求出 1i11 \sim {i-1} 中结尾不等于 xx 的“完整配对子序列”的长度的最大值。考虑将所有的“完整配对子序列”的长度的最大值插入一个数据结构,把结尾等于 xx 的最大值删除,最后求最大值即可。

因此我们需要一个可以快速动态插入、删除、求最大值的数据结构,使用 multiset 即可。注意 multiset 要删除单个某个数不能直接删除,得先 find 到这个数,再删除 find 出来的迭代器。

#include <iostream>
#include <iomanip>
#include <cmath>
#include <string>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <set>
#define int long long
#define endl '\n'
#define IL inline
using namespace std;
const int N = 5e5 + 10;
const int INF = 0x3f3f3f3f;

IL int read()
{
	int x = 0,f = 1;
	char c = getchar();
	while(c <'0'|| c >'9'){if(c == '-') f = -1;c = getchar();}
	while(c >= '0' && c <= '9') x = x * 10 + c - '0',c = getchar();
	return x * f;
}

void write(int x)
{
	if(x > 9) write(x / 10);
	putchar(x % 10 + '0');
}

int n, a[N];
int ans, com[N], inc[N];

multiset <int> st;

signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin >> n;
	for(int i = 1;i <= n;i++) cin >> a[i];
	for(int i = 1;i <= n;i++)
	{
		//维护完整子序列
		if(inc[a[i]])
		{
			if(st.find(com[a[i]]) != st.end()) st.erase(st.find(com[a[i]]));
			com[a[i]] = max(com[a[i]], inc[a[i]] + 1);
			st.insert(com[a[i]]);
		}
		//维护不完整子序列
		if(st.find(com[a[i]]) != st.end()) st.erase(st.find(com[a[i]]));
		if(st.size()) inc[a[i]] = max(inc[a[i]], (*st.rbegin()) + 1ll);
		else inc[a[i]] = max(inc[a[i]], 1ll);
		st.insert(com[a[i]]);
		ans = max(ans, *st.rbegin());
	}
	cout << ans << endl;
	return 0;
}
posted @ 2024-10-13 12:31  邻补角-SSA  阅读(19)  评论(0)    收藏  举报  来源