Dilworth 定理
一个奇技淫巧
P1020 [NOIP1999 普及组] 导弹拦截

题目分析:
第一问显然是求最长不上升子序列,二分优化即可(这个地方也算个不大不小的难点吧,自行查阅即可,不难)。
第二问需要用到 Dilworth 定理:一个序列最少的最长不上升子序列数量等于其最长上升子序列的长度。
证明就是:
假设我们已经将序列划分为数量最少的 k k k个最长不上升子序列,那么我们必然可以在每个序列里面选出一个元素,使得这些元素组成单调递增的一个序列。
否则假设序列 x x x没有选出来任何一个元素。那么考虑 x x x的末尾元素,首先如果把所有最长不上升子序列按照末尾编号的话, x x x不可能是第一个最长不上升子序列。否则 x x x只需要选择末尾元素就可以了。
因此 x x x前面一定存在一个最长不上升子序列已经结尾了,可以直接把 x x x拼接过去,这样就构造了一种情况使得划分的最长不上升子序列的数量减少,矛盾。
因此此时设整个数组的最长上升子序列的长度为 t t t,则 k ≤ t k\leq t k≤t。
并且一个序列只能选出一个数,如果在任意一个不上升子序列内选出两个数,那么这个序列就不可能不上升了。因此 k ≥ t k\geq t k≥t。
则 k = t k=t k=t
如果不能理解 Dilworth 定理,也可以试试这种说法:

引用自 离散小波变换°
示例代码:
#include<iostream>
#include<algorithm>
using namespace std;
int&merge(int f[],int l,int r,int x) {
//在一个不升序列中找到第一个<=x的数字
if(l==r) return f[l];
int mid=l+r>>1;
if(f[mid]<x) return merge(f,l,mid,x);
else return merge(f,mid+1,r,x);
}
int main() {
const int N=1.1e5;
int a[N],f[N],n=1;
int x;
while(cin>>x) a[n++]=x;
n--;
for(auto&i:f) i=0;
int cnt=1;
f[cnt]=a[1];
for(int i=2;i<=n;i++) {
if(a[i]<=f[cnt]) f[++cnt]=a

本文介绍了Dilworth定理及其在求解序列中最长不上升子序列问题中的应用,证明了序列的最长上升子序列数量等于最长下降子序列数量。此外,还探讨了单调队列在优化动态规划中的作用,特别是在处理滑动窗口最值问题中的应用。文章通过实例代码展示了如何使用单调队列解决这类问题。
&spm=1001.2101.3001.5002&articleId=126452951&d=1&t=3&u=2ffd38ea278c4725996a4738f2fe3e72)
2937

被折叠的 条评论
为什么被折叠?



