最长上升子序列,相等的元素不能重复加入这个序列,只能上升,不能水平。
先说一下超时的代码
dp[i] 记录到 i 为止,最长的长度。
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int a[40005];
int main()
{
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
for(int i=0;i<n;i++)
cin>>a[i];
int res=0;
int dp[40005];
for(int i=0;i<n;i++)
{
dp[i]=1;
for(int j=0;j<i;j++)
if(a[i]>a[j]) dp[i]=max(dp[i],dp[j]+1); // i不动,但是dp[i] 一直在变,所以要用 max
res=max(res,dp[i]);
}
cout<<res<<endl;
// cout<<*max_element(dp,dp+n)<<endl;
}
return 0;
}
这个是AC的代码
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstdio>
#define inf 1000000007
using namespace std;
typedef long long ll;
int a[40005],b[40005]={1};
int main ()
{
// freopen("in.txt","r",stdin);
// freopen("date.out","w",stdout);
int t;
cin>>t;
while(t--)
{
int n;
cin>>n;
for(int i=0;i<n;++i)
{cin>>a[i]; b[i]=1;}
b[0]=a[0];
int len=0;
for(int i=1;i<n;++i)
{
if(a[i]>b[len])
b[++len]=a[i];
else
{
int j=lower_bound(b,b+len+1,a[i])-b;
b[j]=a[i];
}
}
cout<<len+1<<endl;
}
return 0;
}
另一种写法
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
int a[40005];
int dp[40005];
const int INF=0x3f3f3f3f;
int main()
{
int t;
cin>>t;
while(t--)
{
memset(dp,0x3f,sizeof dp);
int n;
cin>>n;
for(int i=0;i<n;i++)
cin>>a[i];
for(int i=0;i<n;i++)
*lower_bound(dp,dp+n,a[i])=a[i]; // 在dp 里面找到第一个大于等于 a[i] 的位置,并把a[i] 放在这个位置,代替以前的数
// 以前的数要不是 INF 要不是 延长的序列的最后一个(不是最优的,,,不够小的)值,
// 原数组是 1 1 2 3 6 4 5
// dp里面 放 1 1 2 3 6
// 在看 a[5]的时候 发现 4比6(dp 延伸的最后一位)小,可以把 4 放在这里,有利于 dp 的延伸。
cout<<lower_bound(dp,dp+n,INF)-dp<<endl;
}
return 0;
}
总结一下:
第一种方法,n*n 的 是针对每个a[i] 来找到对应的序列长度
第二三种方法 是直接找到最长(最优)的序列。
接下来说一下lower_bound
#include<bits/stdc++.h>
using namespace std;
int main()
{
cout<<"第一组"<<endl;
int a[10]={1,2,2,8,8,8,30,78,83,100};
cout<<*lower_bound(a,a+10,a[3])<<endl; // 这个值
cout<<lower_bound(a,a+10,a[3])-a<<endl;// 他的下标
cout<<"第二组"<<endl;
int b[10]={100,83,78,30,8,8,8,2,2,1};
cout<<*lower_bound(b,b+10,b[3])<<endl; // 这个值
cout<<lower_bound(b ,b+10,b[3])-b<<endl;// 他的下标
cout<<"第三组"<<endl;
int c[10]={1,30,2,8,8,2,100,78,8,83};
cout<<*lower_bound(c,c+10,c[3])<<endl; // 这个值
cout<<lower_bound(c,c+10,c[3])-c<<endl;// 他的下标
return 0;
}
输出:
第一组
8
3
第二组
2686728
10
第三组
100
6
Process returned 0 (0x0) execution time : 0.131 s
Press any key to continue.
只有第一组数据对了,只能操作升序数组。