HDU6592 Beauty Of Unimodal Sequence


Beauty Of Unimodal Sequence

给一个序列,在满足单调递增或者单调递减或者先增后减的最长子序列集合里找到下标字典序最大以及最小的两个子序列,输出这两个子序列里元素的下标。

n≤3×105

moomhxy的题解

先正着求一遍LIS,再反着求一遍LIS,求出每个点作为上升子序列结尾的最大长度和每个点作为下降子序列开头的最大长度。

我们可以枚举这个单峰序列的峰顶是什么,这样最长长度就找到了。

然后考虑怎么构造解。

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

如何找这个下标较小的呢?显然我们希望每种结尾长度的点都越靠前越好。所以用单调栈维护即可。

最大的话找到最后一个顶峰,往前是依次找,往后是找LIS中下标大的。维护方法类似。

时间复杂度 O(n log n),瓶颈在于求LIS。

CO int N=300000+10;
int a[N],dp[N],up[N],down[N];
int h[N],st[N],ans[N];

void real_main(int n){
    fill(dp,dp+n+1,INT_MAX),dp[0]=0;
    for(int i=1;i<=n;++i){
        read(a[i]);
        up[i]=lower_bound(dp+1,dp+n+1,a[i])-dp;
        dp[up[i]]=a[i];
    }
    fill(dp,dp+n+1,INT_MAX),dp[0]=0;
    for(int i=n;i;--i){
        down[i]=lower_bound(dp+1,dp+n+1,a[i])-dp;
        dp[down[i]]=a[i];
    }
    // minimum lexicographic order
    int tot=0;
    int peak=1,height=up[1]+down[1];
    for(int i=2;i<=n;++i)
        if(up[i]+down[i]>height) peak=i,height=up[i]+down[i];
    int top=0;
    h[up[peak]]=a[peak];
    for(int i=peak-1;i;--i){
        if(a[i]>=h[up[i]+1]) continue;
        while(top and up[i]>=up[st[top]]) --top;
        st[++top]=i;
        h[up[i]]=a[i];
    }
    for(;top;--top) ans[++tot]=st[top];
    ans[++tot]=peak;
    for(int i=peak+1;i<=n;++i)
        if(down[i]==down[ans[tot]]-1 and a[i]<a[ans[tot]]) ans[++tot]=i;
    for(int i=1;i<=tot;++i) printf("%d%c",ans[i]," \n"[i==tot]);
    // maximum lexcographic order
    tot=0;
    peak=1,height=up[1]+down[1];
    for(int i=2;i<=n;++i)
        if(up[i]+down[i]>=height) peak=i,height=up[i]+down[i];
    top=0;
    st[++top]=peak;
    for(int i=peak-1;i;--i)
        if(up[i]==up[st[top]]-1 and a[i]<a[st[top]]) st[++top]=i;
    for(;top;--top) ans[++tot]=st[top];
    h[down[peak]]=a[peak];
    for(int i=peak+1;i<=n;++i){
        if(a[i]>=h[down[i]+1]) continue;
        while(tot and down[i]>=down[ans[tot]]) --tot;
        ans[++tot]=i;
        h[down[i]]=a[i];
    }
    for(int i=1;i<=tot;++i) printf("%d%c",ans[i]," \n"[i==tot]);
}
int main(){
    for(int n;~scanf("%d",&n);) real_main(n);
    return 0;
}

HDU什么时候开始支持<bits/stdc++.h>了……

优质内容筛选与推荐>>
1、通过js代码获取地址位置
2、MVC Html.AntiForgeryToken() 防止CSRF攻击
3、整体性能测试剖析
4、《梦断代码》读后感01
5、Silverlight StoryboardManager 故事板管理类


长按二维码向我转账

受苹果公司新规定影响,微信 iOS 版的赞赏功能被关闭,可通过二维码转账支持公众号。

    阅读
    好看
    已推荐到看一看
    你的朋友可以在“发现”-“看一看”看到你认为好看的文章。
    已取消,“好看”想法已同步删除
    已推荐到看一看 和朋友分享想法
    最多200字,当前共 发送

    已发送

    朋友将在看一看看到

    确定
    分享你的想法...
    取消

    分享想法到看一看

    确定
    最多200字,当前共

    发送中

    网络异常,请稍后重试

    微信扫一扫
    关注该公众号