2019 Multi-University Training Contest 2 Beauty Of Unimodal Sequence

13 篇文章 0 订阅

Beauty Of Unimodal Sequence

Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)
Total Submission(s): 645    Accepted Submission(s): 226


 

Problem Description

You are given an array of n integers a1,a2,...,an. We define that a sequence p1,p2,...,pk(k∈[1,n]) is beautiful if and only if these conditions are met:

 ∙ 1≤p1<p2<⋯<pk≤n.

 ∙ There exists t(t∈[1,k]) satisfying ap1<ap2<⋯<apt and apt>apt+1>⋯>apk.

You need to find all the longest beautiful sequences, and output the lexicographically smallest one and the lexicographically largest one in them.

Check the examples below for better understanding.

 

 

Input

There are multiple test cases.

Each case starts with a line containing a positive integer n(n≤3×105).

The second line contains n integers a1,a2,...,an(1≤ai≤109).

It is guaranteed that the sum of Ns in all test cases is no larger than 106.

 

 

Output

For each test case, output two lines, the first of which depicts the lexicographically smallest one in longest beautiful sequences and the second of which depicts the lexicographically largest one in longest beautiful sequences.

 

 

Sample Input

 

7 1 4 2 5 7 4 6 3 1 2 3 3 3 2 1

 

 

Sample Output

 

1 2 4 5 6 1 3 4 5 7 1 2 3 1 2 3 1 2 3 1 2 3

 

 

Source

2019 Multi-University Training Contest 2

 

 

Recommend

liuyiding

 

 

Statistic | Submit | Discuss | Note

题目大意:给一个长度为n的序列,求最长的先上升后下降的子序列,并且输出字典序最小和最大的序列的下标。

解题思路:对于每一个位置i,我们需要维护

pre[i][0] 表示i一定取,1-i最长上升子序列是多长。

pre[i[[1]表示i一定取,1-i最长单峰子序列是多长。

同理维护一个suf[i][2]。

pre[i][1]如何得到?pre[i][1]一定是由i之前 大于a[i]的最大的pre值转移过来的。可以有树状数组维护。

如何更新大于某个数最大的pre[i][1]呢,当然是和pre[i][0]取一个max。

得到前缀和后缀的最长上升和最长单峰,就能求解了。

剩下的就是如何取字典序最小和字典序最大。

以取字典序最小为例子:

题解说将满足要求的序列排序后是递增的。所以对于符合要求的序列,我们从前往后取最前边的就是字典序最小的。

同理从后边依次取就是字典序最大的。

#include<bits/stdc++.h>
#define LL long long
using namespace std;
#define lowb(x) (x&(-x))
#define pb(x) push_back(x)

const int N = 3e5+5;
int n;
int pre[N][2];
int suf[N][2];
int asc[N],a[N];
int desc[N],num[N];

void updsmall(int x,int val)
{
    for(int i=x;i<=n;i+=lowb(i))
        asc[i]=max(asc[i],val);
}

int  asksmall(int x)
{
    int ans=0;
    for(int i=x;i;i-=lowb(i))
        ans=max(ans,asc[i]);
    return ans;
}

void updbig(int x,int val)
{
    for(int i=x;i;i-=lowb(i))
        desc[i]=max(desc[i],val);
}

int  askbig(int x)
{
    int ans=0;
    for(int i=x;i<=n;i+=lowb(i))
        ans=max(ans,desc[i]);
    return ans;
}

void clr()
{
     memset(asc,0,sizeof(asc));
     memset(desc,0,sizeof(desc));
}
vector<int>v;
int ans[N][2];
void solve(int n,int mx)
{
    int cnt=0,f=0;
    for(int i=1;i<=n;i++)
    {
        if(num[i]!=mx)continue;
        if(f)
        {
            if(suf[i][0]+cnt==mx)
                ans[++cnt][0]=i;
        }
        else
        {
            if(pre[i][0]==cnt+1)
                ans[++cnt][0]=i;
            else if(suf[i][0]+cnt==mx)
                ans[++cnt][0]=i,f=1;
        }
    }

    cnt=0;f=0;
    for(int i=n;i>=1;i--)
    {
        if(num[i]!=mx)continue;
        if(f)
        {
            if(pre[i][0]+cnt==mx)
                ans[++cnt][1]=i;
        }
        else
        {
            if(suf[i][0]==cnt+1)
                ans[++cnt][1]=i;
            else if(pre[i][0]+cnt==mx)
                ans[++cnt][1]=i,f=1;
        }
    }

    for(int i=1;i<=mx;i++)printf("%d%c",ans[i][0],i==mx?'\n':' ');
    for(int i=mx;i>=1;i--)printf("%d%c",ans[i][1],i==1?'\n':' ');
}
int main()
{
    while(~scanf("%d",&n))
    {
        clr( );
        v.clear();
        for(int i=1;i<=n;i++)scanf("%d",a+i),v.pb(a[i]);
        sort(v.begin(),v.end());
        v.erase(unique(v.begin(),v.end()),v.end());
        for(int i=1;i<=n;i++)
        {
            a[i]=lower_bound(v.begin(),v.end(),a[i])-v.begin()+1;
        }
        for(int i=1;i<=n;i++)
        {
            int k=asksmall(a[i]-1);
            pre[i][0]=k+1;
            k=askbig(a[i]+1);
            pre[i][1]=k+1;
            updsmall(a[i],pre[i][0]);updbig(a[i],max(pre[i][0],pre[i][1]));
        }
        clr();
        int mx=0;
        for(int i=n;i>=1;i--)
        {
            int k=asksmall(a[i]-1);
            suf[i][0]=k+1;
            k=askbig(a[i]+1);
            suf[i][1]=k+1;

            updsmall(a[i],suf[i][0]);updbig(a[i],max(suf[i][0],suf[i][1]));
            num[i]=max(pre[i][0]+suf[i][0],max(pre[i][1]+suf[i][0],pre[i][0]+suf[i][1]))-1;
            mx=max(mx,num[i]);
        }
        solve(n,mx);
    }
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值