zoukankan      html  css  js  c++  java
  • 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
    ",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
    ",ans[tot]);
        }
        return 0;
    }
    View Code
  • 相关阅读:
    红黑树——以无厚入有间
    红黑树——依天理以神遇
    B-树 分合之道
    B-树 动机与结构
    云心出岫——Splay Tree
    双散列和再散列暨散列表总结
    开放定址法——平方探测(Quadratic Probing)
    [LeetCode 109]
    [LeetCode 110]
    [LeetCode 111]
  • 原文地址:https://www.cnblogs.com/shuaihui520/p/11462361.html
Copyright © 2011-2022 走看看