网址: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$定理。对于其他偏序关系同理。