题意:
给你一个长度为n的数组,让你选出一个序列使得它是这个数组中的最长单峰序列。输出这类序列字典序最小和最大的序列。
题解:
p
r
e
[
i
]
[
0
]
pre[i][0]
pre[i][0] 表示
a
[
i
]
a[i]
a[i] 一定取,序列
a
[
1..
i
]
a[1..i]
a[1..i] 的最长上升子序列长度。
p
r
e
[
i
]
[
1
]
pre[i][1]
pre[i][1] 表示
a
[
i
]
a[i]
a[i] 一定取,序列
a
[
1..
i
]
a[1..i]
a[1..i] 的最长单峰子序列长度。
s
u
f
[
i
]
[
0
]
suf[i][0]
suf[i][0] 表示
a
[
i
]
a[i]
a[i] 一定取,序列
a
[
i
.
.
n
]
a[i..n]
a[i..n] 的最长下降子序列长度。
s
u
f
[
i
]
[
1
]
suf[i][1]
suf[i][1] 表示
a
[
i
]
a[i]
a[i] 一定取,序列
a
[
i
.
.
n
]
a[i..n]
a[i..n] 的最长单峰子序列长度。
那么状态转移的时候我们就可以用两个树状数组维护当前上升序列和当前单峰序列的最大值
至于求字典序最小和最大,由于字典序是可以贪心找的,因为合法时前一位更优那么就是答案更优。所以我们可以一位一位的考虑。如果当前的位置是在某个最长序列中,并且它是正好在我们枚举到的字典序最小|大的当前位置,也就是
p
r
e
[
i
]
[
0
]
=
=
c
n
t
+
1
pre[i][0]==cnt+1
pre[i][0]==cnt+1,那么就记入答案。或者如果它成为下降序列时也是满足的,
s
u
f
[
i
]
[
0
]
+
c
n
t
=
=
m
x
suf[i][0]+cnt==mx
suf[i][0]+cnt==mx那么我们也记入答案。但是对于这种情况,我们之后所考虑的就是下降序列了。
找字典序最大也是同理。
代码有点长,但是分块看的话还是很好理解的
#include<bits/stdc++.h>
using namespace std;
const int N=3e5+5;
int a[N],b[N],pre[N][2],suf[N][2];
int lowbit(int x){return x&(-x);}
int asc[N],desc[N];
void addasc(int x,int v)
{
for(int i=x;i<N;i+=lowbit(i))
asc[i]=max(asc[i],v);
}
int queryasc(int x)
{
int ans=0;
for(int i=x;i;i-=lowbit(i))
ans=max(ans,asc[i]);
return ans;
}
void adddesc(int x,int v)
{
for(int i=x;i;i-=lowbit(i))
desc[i]=max(desc[i],v);
}
int querydesc(int x)
{
int ans=0;
for(int i=x;i<N;i+=lowbit(i))
ans=max(ans,desc[i]);
return ans;
}
struct node
{
int id,p;
bool operator< (const node& aa)const
{
if(p!=aa.p)
return p<aa.p;
return id<aa.id;
}
};
vector<node>vec;
int num[N],ans[N][2];
int main()
{
int n;
while(~scanf("%d",&n))
{
memset(asc,0,sizeof(asc));
memset(desc,0,sizeof(desc));
for(int i=1;i<=n;i++)
{
scanf("%d",&a[i]),b[i]=a[i];
for(int j=0;j<=1;j++)
pre[i][j]=suf[i][j]=ans[i][j]=0;
}
sort(b+1,b+1+n);
int all=unique(b+1,b+1+n)-b-1;
for(int i=1;i<=n;i++)
a[i]=lower_bound(b+1,b+1+all,a[i])-b;
for(int i=1;i<=n;i++)
{
int k=queryasc(a[i]-1);
pre[i][0]=k+1;
k=querydesc(a[i]+1);
pre[i][1]=k+1;
addasc(a[i],pre[i][0]),adddesc(a[i],max(pre[i][1],pre[i][0]));
}
memset(asc,0,sizeof(asc));
memset(desc,0,sizeof(desc));
int mx=0;
for(int i=n;i>=1;i--)
{
int k=queryasc(a[i]-1);
suf[i][0]=k+1;
k=querydesc(a[i]+1);
suf[i][1]=k+1;
addasc(a[i],suf[i][0]),adddesc(a[i],max(suf[i][1],suf[i][0]));
num[i]=max(pre[i][0]+suf[i][0]-1,max(pre[i][1]+suf[i][0]-1,pre[i][0]+suf[i][1]-1));
mx=max(num[i],mx);
}
int f=0;
int cnt=0;
for(int i=1;i<=n;i++)
{
if(num[i]==mx)
{
if(f)
{
if(cnt+suf[i][0]==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=f=0;
for(int i=n;i>=1;i--)
{
if(num[i]==mx)
{
if(f)
{
if(cnt+pre[i][0]==mx)
ans[mx-cnt][1]=i,cnt++;
}
else
{
if(cnt+1==suf[i][0])
ans[mx-cnt][1]=i,cnt++;
else if(pre[i][0]+cnt==mx)
ans[mx-cnt][1]=i,cnt++;
}
}
}
for(int i=1;i<=mx;i++)
printf("%d%c",ans[i][0],i==mx?'\n':' ');
for(int i=1;i<=mx;i++)
printf("%d%c",ans[i][1],i==mx?'\n':' ');
}
return 0;
}
/*
10
10 4 5 8 4 6 8 5 3 10
*/