最长不下降子序列
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;
}
以上是关于最长不下降子序列的主要内容,如果未能解决你的问题,请参考以下文章