目录
题目概述:
题目背景:
不升子序列的定义:每个数都小于等于上一个数。
题目描述:
输入一个长度为n的序列Ai……An, 将此序列分为若干个子序列(不要求连续),使得每个子序列为不升子序列。求最少要分成多少个子序列。
输入格式:
第一行,一个整数n。
第二行,n个整数,分别为Ai。
输出格式:
一个正整数,为最少要分成的子序列个数。
输入样例:
6
2 1 2 7 2 3
输出样例:
3
说明提示:
样例1说明:将{2,1},{2,2},{7,3}分为一组
数据范围:
数据点
N≤
Ai≤
分值(个)
1-2
20
100000
7
3-4
100
8
5-7
1000000
10
8-9
1000000000
13
10
1000000000
1000000
14
注:此题为洛谷私人题库,到
U376600 最小将序列覆盖 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
提交答案
解析:
方法一:暴力算法
这道题我们要用 “贪心算法”。
首先,我们来分析这道题,我们要让子序列最小,一定要让尽可能地接上上一个字符串,我们的贪心策略便出来了:
于是,我们开一个二维数组,然后我们去操作:
首先,第一个数字二,我们放在一个新数组,并将后面接上2:
接着,看1,因为1<2,所以我们接在后面,并重置后面
再看2,因为2>1,所以我们开一个新的并接好后面的
然后,我们继续操作,这里不做详细说明……
最终,表格成为这样:
最后,二维数组的行数变为答案。
接着,程序实现:
但是,很多人都看出来了,这样百分百超时,因为,这是n^2算法!
不过,找到最小的可接子序列可以用二分查找!
但最大的问题可能你们未能发现:空间复杂度!
看来,我们这样的话只能得30分了
方法二:Dilworth 定理
很显然,我们这里可以引用一个著名定理:Dilworth 定理:最⻓链=最⼩反链覆盖
我们可以把最小不升子序列覆盖改为最长上升子序列。
于是,我们编写一个复杂度为n的程序:
简简单单十几行搞定!
如果需要Dilworth定理的证明,请到云剪贴板 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)查看。