http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1475
题目大意:
给定一个长度为n的整数序列,求一个最长子序列(不一定为连续),使得该序列的长度为奇数2*k+1,前k+1个数严格递增,后k+1个数严格递减。(严格递增/递减意味着相邻两个数不能相同)
思路:
可以求两次LIS(最长上升子序列),一次是递增的,一次是递减的(其实就是倒着求递增的)
n高达10000,因此LIS要用二分查找来优化时间复杂度为O(nlogn)
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN=10000+10;
const int INF=0x7fffffff;
int data[MAXN],d1[MAXN],g1[MAXN],d2[MAXN],g2[MAXN];
int search(int L,int R,int x,int *g)
{
while(L<R)
{
int mid=L+(R-L)/2;
if(g[mid] < x)
L=mid+1;
else
R=mid;
}
return L;
}
int main()
{
int n;
while(~scanf("%d",&n))
{
for(int i=0;i<n;i++)
scanf("%d",&data[i]);
for(int i=1;i<=n;i++) g1[i]=g2[i]=INF;
for(int i=0,j=n-1;i<n;j--,i++)
{
//也可以直接用STL函数
int k1=search(1,n+1,data[i],g1);//lower_bound(g1+1,g1+n+1,data[i])-g1;
int k2=search(1,n+1,data[j],g2);//lower_bound(g2+1,g2+n+1,data[j])-g2;
d1[i]=k1;
d2[j]=k2; //记录下标
g1[k1]=data[i]; //求LIS
g2[k2]=data[j]; //逆的LIS
}
int ans=1;
for(int i=0;i<n;i++)
{
ans=max((2*min(d1[i],d2[i])),ans);
}
printf("%d\n",ans-1);
}
return 0;
}