目录
Description
给出一个长度为N的数字串,找出一个严格上升的数字序列来.
Format
Input
第一行给出数字N
接下来给出N个数字
N<=1000
Output
如题
Samples
输入数据 1
7
1 7 3 5 9 4 8
输出数据 1
4
分析
暴力版
注:用f数组保存原数列
这一题,我们很容易可以想到,以结束点为阶段,于是有如下做法:
用dp[i]表示当必须以i为结尾时,可得的最长子序列长度。
初始状态dp[1]=1;
于是for(int i=1;i<=n;i++)
对于每个i,我们可以知道它可以接在i之前任何一个对应值小于它的dp[i]后面
我们用一个临时变量mid记录dp[1……i]中允许的最大值,即:( )
于是一个暴力代码就出来了。
优化版
这一次,我们来记录另一个东西。
我们用一个数组,它的长度(下文称为en)表示当前已经找到的最长上升子序列的长度;
它的内容的递增部分(下文称为u)表示以当前数结尾时产生的最长上升的子序列
思路就很简单了:每扫描到一个数,我们就把它丢到u里面。如果它比u的最后一个数都大的话,就把它放在最后面,同时en++;否则就用lower_bound找到u中第一个大于等于它的数,并替换掉。
一定注意是大于等于
代码
暴力版
#include<bits/stdc++.h>
using namespace std;
int ans,mid;
int n,f[10000];
int dp[10000];
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
cin>>f[i];
for(int i=1;i<=n;i++)
{
mid=0;
for(int j=1;j<i;j++)
if(f[j]<f[i])
mid=max(dp[j],mid);
dp[i]=mid+1;
ans=max(dp[i],ans);
}
cout<<ans;
}
优化版
#include<bits/stdc++.h>
using namespace std;
int ans,mid,k;
int n,f[100000];
int u[100000],en;
int main()
{
en=ans=0;
cin>>n;
memset(u,0,sizeof(u));
for(int i=1;i<=n;i++)
cin>>f[i];
for(int i=1;i<=n;i++)
{
if(!en||u[en]<f[i])
{
en++;
u[en]=f[i];
}
else
{
mid=lower_bound(u+1,u+1+en,f[i])-u;
u[mid]=f[i];
}
}
cout<<en<<endl;
}