CSP难度的经典题目/有趣的思维题选讲(一)

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

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 kt

并且一个序列只能选出一个数,如果在任意一个不上升子序列内选出两个数,那么这个序列就不可能不上升了。因此 k ≥ t k\geq t kt

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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值