codeforces1304D Shortest and Longest LIS Dilworth定理

网址:https://codeforces.com/contest/1304/problem/D

题意:

给出一些长度是$n-1$的偏序关系,然后往这些偏序关系中填入$1$到$n$这$n$个数。求合法的序列中最短和最长的上升子序列的方案。

题解:

$Dilworth$定理:最长不下降子序列长度$=$最少下降子序列的划分$=$最小反链划分。

$Dilworth$定理的对偶定理:最长不上升子序列长度$=$最少上升子序列的划分$=$最大反链划分。

$*Dilworth$定理中反链的解释:设全集$U$是一个偏序集,$U$的子集中,满足其中任意两个元素(不相同)不可比的集合。

根据这个定理首先是求最小的:我们先把所有的$n$个数反着放,然后显然这个是最短的上升子序列。然后对于$'<'$,我们就整段反过来,然后一直这样子处理到结尾。为什么这样做是对的呢?因为这样子一定是最少的上升子序列的划分,对于最大的,同理操作即可。

AC代码:

#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
int mx[N], mi[N];
char s[N];
void solve()
{
	int n;
	scanf("%d%s", &n, s + 1);
	for (int i = 1; i <= n; ++i)
		mx[i] = i, mi[i] = n - i + 1;
	for (int i = 1; i < n;)
	{
		char ch = s[i];
		int k = i + 1;
		while (k < n && s[k] == s[i])
			++k;
		if (ch == '<')
			reverse(mi + i, mi + k + 1);
		else
			reverse(mx + i, mx + k + 1);
		i = k;
	}
	for (int i = 1; i <= n; ++i)
		printf("%d%c", mi[i], " 
"[i == n]);
	for (int i = 1; i <= n; ++i)
		printf("%d%c", mx[i], " 
"[i == n]);
}
int main()
{
	int t;
	scanf("%d", &t);
	while (t--)
		solve();
	return 0;
}

$*$为什么能得到上面那个连等关系:

把序列转化成集合,我们发现对于一个序列的元素,有两个量描述:使用有序数对$(p,v)$表示原序列中的一个数。$p$表示位置,$v$表示数值。对于求最长不下降子序列的,应该满足的关系是$p1<=v1$且$p2<=v2$,这是个偏序关系显然可比。所以满足$Dilworth$定理。对于其他偏序关系同理。

原文地址:https://www.cnblogs.com/Aya-Uchida/p/12319146.html