HDU 6592 (LIS+输出字典序最大最小)

题意:给你一个序列,让你找长度最长的字典序最小和最大的单峰序列,单峰序列就是满足先增后降的序列。

思路:先正着求一遍LIS,再反着求一遍LIS,然后用单调栈来模拟。

求字典序最小的话,首先找到第一个顶峰,然后往前找递减的序列中下标较小的,往后就依次找,这样能保证字典序最小。

最大的话找到最后一个顶峰,往前是依次找,往后是找LIS中下标大的。

#include<bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
const int N = 3e5+10;
int d[N],pos1[N],pos2[N],a[N],p[N],ans[N];
int main(){
    int n;
    while(~scanf("%d",&n)){
        for(int i=0 ; i<=n ; i++)
            d[i]=INF,p[i]=INF;
        d[0]=0;
        for(int i=1 ; i<=n ; i++){///正向LIS
            scanf("%d",&a[i]);
            pos1[i]=lower_bound(d+1,d+1+n,a[i])-d;
            d[pos1[i]]=a[i];
        }
        for(int i=0 ; i<=n ; i++)
         d[i]=INF;
         d[0]=0;
         for(int i=n ; i>=1 ; i--){///反向LIS
            pos2[i]=lower_bound(d+1,d+1+n,a[i])-d;
            d[pos2[i]]=a[i];
         }
         int now=1,mx=pos1[1]+pos2[1],tot=0;///找到最小秃顶
         for(int i=2 ; i<=n ; i++)
         {
             if(pos1[i]+pos2[i]>mx){
                mx=pos1[i]+pos2[i];
                now=i;
             }
         }
         ///找字典序最小就是正找小反找大(仔细一想是这么一回事)
         stack<int>st;
         p[pos1[now]]=a[now];/// pos1[now]--长度的尾巴是a[now]
         for(int i=now-1;i>=1;i--){
            if(a[i]>=p[pos1[i]+1]) continue;///排除不合格的条件 -> 6 5 (把6排除)
            while(!st.empty()&&pos1[st.top()]<=pos1[i]) st.pop(); ///在可选的,选择下标小的
            st.push(i);
            p[pos1[i]]=a[i];
         }
         while(!st.empty()){
            ans[++tot]=st.top();
            st.pop();
         }
         ans[++tot]=now;
         ///反向最大就是一直调下去
         for(int i=now+1 ; i<=n ; i++){
            if(pos2[i]==pos2[ans[tot]]-1&&a[ans[tot]]>a[i])
                ans[++tot]=i;
         }
         for(int i=1;i<tot;i++)
            printf("%d ",ans[i]); printf("%d\n",ans[tot]);
         now=1; mx=pos1[1]+pos2[1]; tot=0;
         for(int i=2;i<=n;i++){///找到最大秃顶
            if(pos1[i]+pos2[i]>=mx){
                mx=pos1[i]+pos2[i];
                now=i;
            }
         }
         ///找字典序最大就是正找大反找小
         st.push(now);
         for(int i=now-1;i>=1;i--){
            if(pos1[i]==pos1[st.top()]-1&&a[i]<a[st.top()]){
                st.push(i);
            }
         }
         while(!st.empty()){
            ans[++tot]=st.top();st.pop();
         }

        for(int i=0 ; i<=n ; i++)
            p[i]=0;
         p[pos2[now]]=a[now];

         for(int i=now+1;i<=n;i++){
            if(a[i]>=p[pos2[i]+1]) continue;
            while(tot>0&&pos2[i]>=pos2[ans[tot]]) tot--;
            ans[++tot]=i;
            p[pos2[i]]=a[i];
         }
         for(int i=1;i<tot;i++)
            printf("%d ",ans[i]); printf("%d\n",ans[tot]);
    }
    return 0;
}
View Code

 

posted @ 2019-09-04 23:25  shuai_hui  阅读(435)  评论(0编辑  收藏  举报