HDU 4604

来源:互联网 发布:windows pe u盘版 iso 编辑:程序博客网 时间:2024/05/24 06:31

求双队列的最长非递减序列

考虑题目的一个简化版本:使双端队列单调上升。

找到队列中最早出现的数组Ax,则Ax将Q分成的两个部分分别是原序列中以Ax开始的最长上升子序列和最长下降子序列。

答案即为这两者之和的最大值,而对于本题,由于存在相同元素,所以只要找到以Ax为起点的最长不下降序列和最长不上升序列的和,

然后减去两个里面Ax次数的最小值。(比如1 2 3 1 1。最长不下降1 2 3,最长不上升1 1 1,只有开头的1被共用)

STL 的使用

upper_bound对从小到大排序的数组进行二分查找

equal_range其实就是upper-lower



#include<cstdio>#include<iostream>#include<vector>#include<algorithm>using namespace std;const int N=100002;int n,a[N],dp_up[N],dp_down[N],num_up[N],num_down[N];vector<int> v;vector<int>::iterator iter;void getdp(int dp[],int num[]){v.clear();v.push_back(a[n-1]);for(int i=n-2;i>=0;i--){int sz=v.size();if(a[i]>v[sz-1]){v.push_back(a[i]);dp[i]=sz+1;num[i]=1;}else if(a[i]==v[sz-1]){v.push_back(a[i]);dp[i]=sz+1;pair<vector<int>::iterator,vector<int>::iterator> bound;bound=equal_range(v.begin(),v.end(),a[i]);num[i]=bound.second-bound.first;}else{iter=upper_bound(v.begin(),v.end(),a[i]);dp[i]=iter-v.begin()+1;*iter=a[i];pair<vector<int>::iterator,vector<int>::iterator> bound;bound=equal_range(v.begin(),v.end(),a[i]);num[i]=bound.second-bound.first;}}}int main(){int tt,i,tmp;for(cin>>tt;tt>0;tt--){cin>>n;for(i=0;i<n;i++)scanf("%d",&a[i]);getdp(dp_down,num_down);for(int i=0;i<n;i++)a[i]=-a[i];getdp(dp_up,num_up);int ans=0;for(int i=0;i<n;i++){int tot=dp_up[i]+dp_down[i]-min(num_up[i],num_down[i]);if(tot>ans)ans=tot;}printf("%d\n",ans);}return 0;}
不用动态数组实现
int stack[N],cnt;void getdp(int dp[],int num[]){//O(nlogn)cnt=0;stack[cnt++]=a[n-1];for(int i=n-2;i>=0;i--){if(a[i]>stack[cnt-1]){stack[cnt++]=a[i];dp[i]=cnt;num[i]=1;}else if(a[i]==stack[cnt-1]){stack[cnt++]=a[i];dp[i]=cnt;pair<int*,int*> bound;bound=equal_range(stack,stack+cnt,a[i]);num[i]=bound.second-bound.first;}else{int iter=upper_bound(stack,stack+cnt,a[i])-stack;dp[i]=iter+1;stack[iter]=a[i];pair<int*,int*> bound;bound=equal_range(stack,stack+cnt,a[i]);num[i]=bound.second-bound.first;}}}
0 0
原创粉丝点击