最长上升(下降)(不上升)(不下降)子序列,和dilworth定理
最长**子序列是动态规划中的经典问题,而dilworh定理也是其中重要的一环。
经典的问题那必然也就有经典的例题
P1020 [NOIP1999 普及组] 导弹拦截
题目中第一问要我们求最长不上升子序列。
具体的做法是:
假设我们现在有一个不上升序列 5 4 2 2
然后我们碰到了一个数字3,现在序列中的最后一个数比3小
但是当我们选择取3的话可以使得之后可以选取的数字更多(3,2,1)
所以我们考虑先不让这个序列增加,使用3将序列中第一个比3小的数字剔除掉
为什么可以剔除呢
因为剔除之后序列的长度并没有改变,而且当之后遇到小于2的数字的时候依然可以添加到队列的末尾
而要找到第一个比三小的数我们可以用upper_bound函数,其他的就看代码吧
#include<iostream> #include<algorithm> #include<cmath> #include<string.h> using namespace std; int a[200005], n = 0, stac[200005], now = 0; int main() { while (cin >> a[++n]); n--; for (int i = 1; i <= n; i++) { if (stac[now] >= a[i] || i == 1) { stac[++now] = a[i]; } else { int x = upper_bound(stac + 1, stac + now + 1, a[i], greater<int>()) - stac; stac[x] = a[i]; } } cout << now << endl; memset(stac, 0, sizeof(stac)); now = 0; for (int i = 1; i <= n; i++) { if (stac[now] < a[i] || i == 1) { stac[++now] = a[i]; } else { int x = lower_bound(stac + 1, stac + now + 1, a[i]) - stac; stac[x] = a[i]; } } cout << now << endl; return 0; }
而第二问中要我们求需要多少套设备该怎么办呢。
其实就是要我们求要求几次最长不上升子序列才能将导弹全部选完。
具体为什么我们不妨看看这篇博客 https://www.cnblogs.com/Gaomez/p/14324357.html
那要怎么求呢
我们可以借助dilworth定理
大概意思就是当我们要求一个最长**子序列数量的时候就是要求与其相反的最长子序列的长度。
比如这题我们要求最长不上升子序列数量,就是要求最长上升子序列的长度,明白了这个这题就很清楚了。

浙公网安备 33010602011771号