最长上升子序列就是指在一个序列中,求出一个最长的子序列满足单调递增,同时各个元素在原序列中不要求连续。
这个方法很巧妙,不妨进行如下考虑:对于序列中的元素A[x]
首先有,B[1]=A[1]=4且len=1。
接着考虑A[2],有B[1]=2,len=1,对于A[3],因为A[3]>B[len],所以有len=len+1,B[len]=6
考虑A[4],可有B[2]=3,考虑A[5],无法插入数组B,考虑A[6],有len=len+1,B[len]=5。
故最终len=3,B[i]={2,3,5}。
其核心代码是:
scanf("%d",&T);
for(int kase=1;kase<=T;kase++)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
b[1]=a[1];
len=1;
for(int i=2;i<=n;i++)
if(a[i]>b[len]) b[++len]=a[i];
else
{
int pos=lower_bound(b+1,b+1+len,a[i])-b;
b[pos]=a[i];
}
printf("%d\n",len);
}
一道例题如下:
A序列
发布时间: 2017年7月9日 20:20 最后更新: 2017年7月10日 21:11 时间限制: 1000ms 内存限制: 128M
如果一个序列有奇数个正整数组成,不妨令此序列为a1,a2,a3,...,a2∗k+1(0<=k),并且a1,a2...ak+1是一个严格递增的序列,ak+1,ak+2,...,a2∗k+1,是一个严格递减的序列,则称此序列是A序列。
比如1 2 5 4 3就是一个A序列。
现在Jazz有一个长度为n的数组,他希望让你求出这个数组所有满足A序列定义的子序列里面最大的那个长度。(子序列可以不连续)
比如1 2 5 4 3 6 7 8 9,最长的A序列子串是1 2 5 4 3。
多组输入,每组两行。
第一行是n,表示给的数组的长度。
第二行有n个数(int范围),即给你的数组。
1<=n<=500000
每组输入输出一行,即最长的A序列子串的长度。
9 1 2 5 4 3 6 7 8 9
5
长下降子序列,取这二者的最小值,然后再将该值乘以二减一得到每个点对应的A序列。然后遍历这个序列,将每一
个点这样扫一遍即可。
最长上升子序列和最长下降子序列可以使用模板,这里就不详细说明了。
下面是ac代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#include<algorithm>
#include<queue>
#include<stack>
#include<vector>
#include<cmath>
#include<iomanip>
#define ll long long
#define INF 0x3f3f3f3f
#define mod 1e9+7
#define clr(a,x) memset(a,x,sizeof(a))
using namespace std;
const double eps = 1e-6;
#define N 500001
int num[N],temp[N],ans[N],l[N],r[N];
int main()
{
int n;
while(scanf("%d",&n)==1)
{
for(int i=1;i<=n;i++)
{
scanf("%d",&num[i]);
}
int Max=1;
clr(temp,INF);
temp[0]=-1;
for(int i=1;i<=n;i++)
{
int pos=lower_bound(temp,temp+n,num[i])-temp;
temp[pos]=num[i];
Max=max(Max,pos);
l[i]=Max;
}
Max=1;
clr(temp,INF);
temp[0]=-1;
for(int i=n;i>=1;i--)
{
int pos=lower_bound(temp,temp+n,num[i])-temp;
temp[pos]=num[i];
Max=max(Max,pos);
r[i]=Max;
}
int ans=1;
for(int i=1;i<=n;i++)
{
ans=max(ans,min(l[i],r[i]));
}
printf("%d\n",ans*2-1);
}
return 0;
}