求一个序列中 的2*n-1个数字 ,前n+1个数字为严格升序 后n+1个为严格降序,求最长的长度
一开始还没想清楚怎么解,其实就是一个LCS问题,从头到尾以及反序求一下LCS
由于 d[i]为包含了自身的LCS,所以每次比较 min(d1[i],d2[i]),再 2*min-1即可,d1和d2分别为正序和反序的LCS。
由于时间卡的紧,要用之前学过的压栈法求LCS,时间复杂度为n*logn,中间出了一些问题,首先就是保存每个节点的LCS值的时候,如果该点是大于sta[top],那自然LCS为top+1,但是如果不是的话,我一开始写成top,原来不是,是要二分的那个位置才是。。。。还有就是二分一开始调用的是Upper_bound,错了,应该是lower_bound
再复习下 upper_bound是找大于val的第一个位置点,如果val小于整个序列,返回 0,如果val大于整个序列,返回数组的最后一位+1。
lower_bound是找大于并等于val的第一个值,如果序列中没有==val的,那跟upper是一样的效果,如果有相同的,并且同时有几个相同的,则返回第一个相同的数的下标。上界和下界是跟upper一样的。
#include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #include <algorithm> #define N 10010 using namespace std; int d1[N],d2[N],A[N]; int n,sta[N]; void init() { int top=0; sta[0]=-1; sta[++top]=A[1]; d1[1]=1; for (int i=2;i<=n;i++) { if (A[i]>sta[top]){ sta[++top]=A[i]; d1[i]=top; } else { int loc=lower_bound(sta+1,sta+top+1,A[i])-sta; sta[loc]=A[i]; d1[i]=loc; } } top=0; sta[++top]=A[n]; d2[n]=1; for (int i=n-1;i>=1;i--) { if (A[i]>sta[top]){ sta[++top]=A[i]; d2[i]=top; } else { int loc=lower_bound(sta+1,sta+top+1,A[i])-sta; sta[loc]=A[i]; d2[i]=loc; } } } void test() { for (int i=1;i<=n;i++) { printf("%d %d ",d1[i],d2[i]); } } int main() { while (scanf("%d",&n)!=EOF) { for (int i=1;i<=n;i++) { scanf("%d",&A[i]); } init(); //test(); int ans=0; for (int i=1;i<=n;i++) { int tmp=min(d1[i],d2[i]); ans=max(ans,2*tmp-1); } printf("%d ",ans); } return 0; }