hdu 4604 Deque

来源:互联网 发布:js json数组排序 编辑:程序博客网 时间:2024/05/19 17:52

总体思想就是二分的LIS+标记重复的数

从后往前遍历数组:                         

每运行一个数的时候,可以找出从这个数到数组尾的最长不上升子序列的长度num和最长不下降子序列的长度nums。                

然后用sum标记这个数在最长不上升子序列中存在的个数,用sums标记这个数在最长不下降子序列中存在的个数。                

然后如果 deque数组中第一个放入的数是这个数的话, deque的长度就等于num+nums-min(sum,sums);

遍历一边之后,找出最大的数就可以了。



#include<stdio.h>#include<iostream>#include<algorithm>#include<string.h>using namespace std;struct list{int i;int x;int y;}node[200001];int num[200005];int len[200005];int sum[200005];int lens[200005];int sums[200005];int cmp1(list a,list b){return a.x<b.x;}int cmp2(list a,list b){return a.i<b.i;}int main(){int T,n,i;scanf("%d",&T);while(T--){scanf("%d",&n);for(i=0;i<n;i++){scanf("%d",&node[i].x);node[i].i=i;}sort(node,node+n,cmp1);int leap=2;node[0].y=1;for(i=1;i<n;i++){if(node[i].x==node[i-1].x)node[i].y=node[i-1].y;else node[i].y=leap++;}sort(node,node+n,cmp2);for(i=0;i<n;i++)num[i]=node[n-i-1].y;int l,r;l=r=0;len[r++]=num[0];memset(sum,0,sizeof(sum));sum[num[0]]++;int ls,rs;ls=rs=0;lens[rs++]=num[0];memset(sums,0,sizeof(sums));sums[num[0]]++;int maxnn;maxnn=1;for(i=1;i<n;i++){int l1,l2,mid;if(num[i]>=len[r-1]){len[r++]=num[i];sum[num[i]]++;l1=r;}else{    l=0;    int rr=r;while(l<r){mid=(l+r)/2;if(len[mid]<=num[i])l=mid+1;else if(len[mid]>num[i]&&(mid==0||len[mid-1]<=num[i]))break;else r=mid;}sum[len[mid]]--;sum[num[i]]++;len[mid]=num[i];l1=mid+1;r=rr;}if(num[i]<=lens[rs-1]){lens[rs++]=num[i];sums[num[i]]++;l2=rs;}else{    ls=0;    int rr=rs;while(ls<rs){mid=(ls+rs)/2;if(lens[mid]>=num[i])ls=mid+1;else if(lens[mid]<num[i]&&(mid==0||lens[mid-1]>=num[i]))break;else rs=mid;}sums[lens[mid]]--;sums[num[i]]++;lens[mid]=num[i];l2=mid+1;rs=rr;}if(maxnn<(l1+l2-min(sum[num[i]],sums[num[i]])))maxnn=l1+l2-min(sum[num[i]],sums[num[i]]);}cout<<maxnn<<endl;}return 0;}