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);
}
}