码迷,mamicode.com
首页 > 其他好文 > 详细

最长不下降子序列

时间:2019-01-30 20:27:37      阅读:173      评论:0      收藏:0      [点我收藏+]

标签:时间   bit   ++   复习   class   turn   space   结合   价值   

最近想复习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\n",ans);
    return 0;
}

最长不下降子序列

标签:时间   bit   ++   复习   class   turn   space   结合   价值   

原文地址:https://www.cnblogs.com/NLDQY/p/10339592.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!