题目大意:
多组数据,先给
t
t
t表示数据组数,给一个
1
1
1到
n
n
n的排列,问是否可以变成一个上升序列和一个下降序列拼起来,并输出上升序列的长度以及这个上升序列,下降序列同理。(语文不太好···
给个样例就是:
输入:
3
5
5 1 4 2 3
5
1 2 3 5 4
1
1
输出:
YES
2 1 2
3 5 4 3
YES
3 1 2 3
2 5 4
YES
0
1 1
数据范围: t < = 50 , t<=50, t<=50, n < = 100000 n<=100000 n<=100000
solution:
第一眼看到这个数据范围就想到了贪心什么的···
反正差不多是
O
(
N
)
O(N)
O(N)做,也想过
d
p
dp
dp,但感觉用一般的
d
p
dp
dp很不现实
所以就想贪心,但是这个题贪心是错的
真的是
d
p
dp
dp啊我还是太
n
a
i
v
e
naive
naive了
但是要考虑
d
p
dp
dp状态如何设计,果然不是一般的
d
p
dp
dp状态
也不是
l
i
s
lis
lis不要想多了
设 d p [ i ] dp[i] dp[i]表示以 i i i为上升序列的结尾,最大的下降序列结尾(值)是什么
可以这样设计是因为,已经知道了这个序列一定是由上升和下降序列构成的,所以只要考虑一个的状态,在这个状态下让另一个更优就一定会找到可行解。
然后考虑转移,首先他能
O
(
n
2
)
做
,
O(n^2)做,
O(n2)做,有一个
O
(
n
l
o
g
n
)
O(nlogn)
O(nlogn)的方法就是线段树优化前缀最大值
e
m
m
m
emmm
emmm十分暴力很卡常
一个很厉害的
O
(
n
)
d
p
O(n)dp
O(n)dp就是考虑大力分类讨论,
p
r
e
[
i
]
pre[i]
pre[i]记录上升序列的前一个的下标方便输出,还要记录一个
m
v
mv
mv表示如果
i
−
1
i-1
i−1和
i
i
i不在一个上升序列时前面可以接上
i
i
i的
这么说不太直观还是看代码吧 q w q qwq qwq
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define maxn 100005
using namespace std;
int t,n,a[maxn],dp[maxn],pre[maxn]; bool used[maxn];
inline int rd(){
int x=0,f=1;char c=' ';
while(c<'0' || c>'9') f=c=='-'?-1:1,c=getchar();
while(c<='9' && c>='0') x=x*10+c-'0',c=getchar();
return x*f;
}
int main(){
freopen("quin.in","r",stdin);
freopen("quin.out","w",stdout);
t=rd();
while(t--){
n=rd();
for(int i=1;i<=n;i++) a[i]=rd();
a[n+1]=n+2; dp[0]=n+1;
int mv=0;
for(int i=1;i<=n+1;i++){
dp[i]=-1;//记得初始化!
if(a[i-1]<a[i]) dp[i]=dp[i-1],pre[i]=i-1;//i和i-1组成上升
if(mv!=-1 && a[mv]<a[i] && a[i-1]>dp[i]) dp[i]=a[i-1],pre[i]=mv;//i和mv组成上升
if(i!=1 && a[i-1]<a[i]) mv=-1;//重新找上升的结尾
if(dp[i-1]>a[i] && (mv==-1||a[mv]>a[i-1]))
mv=i-1;//i可以作为下降的结尾,i-1为上升结尾
}
if(dp[n+1]==-1){
puts("NO"); continue;
}
memset(used,0,sizeof used);
puts("YES");
int u=n+1,tot=0;
while(u!=0) used[u]=1,u=pre[u];//找出上升的
for(int i=1;i<=n;i++)
if(used[i]) tot++;
printf("%d ",tot);
for(int i=1;i<=n;i++)
if(used[i]) printf("%d ",a[i]);
printf("\n%d ",n-tot);
for(int i=1;i<=n;i++)
if(!used[i]) printf("%d ",a[i]); printf("\n");
}
return 0;
}