当前位置: 代码迷 >> 综合 >> hdu 4604 Deque
  详细解决方案

hdu 4604 Deque

热度:43   发布时间:2023-12-19 11:16:34.0

总体思想就是二分的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;
}


  相关解决方案