最长不下降子序列

Posted nldqy

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了最长不下降子序列相关的知识,希望对你有一定的参考价值。

最近想复习dp,于是先来水一篇博客。。。

如何来求一个一串长度为(n)的数列的最长不下降子序列呢?

(dp[i])表示所有长度为(i)的不下降子序列的最小结尾数字。

也就是说(dp[i]={min(j)|len[j]=i})(len[j])表示以(j)结尾的不下降子序列长度(实际代码并不要用上这个数组)。

然后就可以愉快的开始dp啦!

初始化(dp[1]=a[1],ans=1),从2开始dp

对于每一个(a[i]),若(a[i]ge dp[ans]),那么它就可以更新当前答案,所以就令(dp[++ans]=a[i])

若小于呢?则我们需要用上dp数组的单调性了。

我们先来看看dp数组的定义:(dp[i]={min(j)|len[j]=i})

再结合更新过程,我们显然可以得出(dp[i]ge dp[i-1])的性质

所以如果小于,我们就在(dp[1,,to,,ans])中找到第一个大于(a[i])的数,把它替换成(a[i])

此时,因为它是第一个大于(a[i])的,所以它之前的数肯定都小于(a[i]),所以(a[i])完全可以代替它,且因为(a[i])比它要小,所以带来的价值会更高(贪心)。

具体实现我们可以用STL中的upper_bound(毕竟学的都是C with STL 滑稽.jpg)。时间复杂度(O(n,,log,,n))

Code:

#include<bits/stdc++.h>
using namespace std;
int n,ans;
int a[100001],dp[100001];
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++) scanf("%d",&a[i]);
    dp[1]=a[1];ans=1;
    for(int i=2;i<=n;i++){
        if(a[i]>=dp[ans]) dp[++ans]=a[i];
        else {
            int x=upper_bound(a+1,a+ans+1,a[i])-a;
            dp[x]=a[i]; 
        }
    }
    printf("%d
",ans);
    return 0;
}

以上是关于最长不下降子序列的主要内容,如果未能解决你的问题,请参考以下文章

最长不下降子序列

最长不下降子序列

「模板」最长不下降子序列 LIS

最长不下降子序列 nlogn && 输出序列

最长不下降子序列 (O(nlogn)算法)

单调栈最长不下降子序列变式