思路
构建状态表示:
d
p
[
i
]
[
1
]
dp[i][1]
dp[i][1] 代表在前 i 位中,若第 i 位为升序序列结尾,此时降序序列结尾的最大值;
o
p
[
i
]
[
1
]
op[i][1]
op[i][1] 代表若第 i 位为升序序列结尾,
d
p
[
i
]
[
1
]
dp[i][1]
dp[i][1]取当前值时,第 i-1 位在升序序列 / 降序序列(1升0降);
d
p
[
i
]
[
0
]
dp[i][0]
dp[i][0] 代表在前 i 位中,若第 i 位为降序序列结尾,此时升序序列结尾的最小值;
o
p
[
i
]
[
0
]
op[i][0]
op[i][0] 代表若第 i 位为降序序列结尾,
d
p
[
i
]
[
0
]
dp[i][0]
dp[i][0]取当前值时,第 i-1 位在升序序列 / 降序序列(1升0降);
定义初值:
d
p
[
i
]
[
1
]
=
−
i
n
f
,
d
p
[
i
]
[
1
]
=
i
n
f
dp[i][1]=-inf,dp[i][1]=inf
dp[i][1]=−inf,dp[i][1]=inf 即每一位默认是不能参与序列的,直至转移方程时满足条件才可更新;
特殊地,
d
p
[
1
]
[
1
]
=
i
n
f
,
d
p
[
1
]
[
0
]
=
−
i
n
f
dp[1][1]=inf,dp[1][0]=-inf
dp[1][1]=inf,dp[1][0]=−inf 即第一位既可以在升序序列,也可以在降序序列;
状态转移方程:
d
p
[
i
]
[
1
]
=
d
p
[
i
−
1
]
[
1
]
,
o
p
[
i
]
[
1
]
=
1
;
(
a
[
i
−
1
]
<
a
[
i
]
&
&
d
p
[
i
]
[
1
]
<
d
p
[
i
−
1
]
[
1
]
)
dp[i][1] = dp[i - 1][1],op[i][1] = 1;(a[i - 1] < a[i] \&\& dp[i][1] < dp[i - 1][1])
dp[i][1]=dp[i−1][1],op[i][1]=1;(a[i−1]<a[i]&&dp[i][1]<dp[i−1][1]) 此位接在前位后做升序序列
d
p
[
i
]
[
1
]
=
a
[
i
−
1
]
,
o
p
[
i
]
[
1
]
=
0
;
(
d
p
[
i
−
1
]
[
0
]
<
a
[
i
]
&
&
d
p
[
i
]
[
1
]
<
a
[
i
−
1
]
)
dp[i][1] = a[i - 1],op[i][1] = 0;(dp[i - 1][0] < a[i] \&\& dp[i][1] < a[i - 1])
dp[i][1]=a[i−1],op[i][1]=0;(dp[i−1][0]<a[i]&&dp[i][1]<a[i−1]) 前位做降序序列结尾,此位做升序序列结尾
d
p
[
i
]
[
0
]
=
d
p
[
i
−
1
]
[
0
]
,
o
p
[
i
]
[
0
]
=
0
;
(
a
[
i
−
1
]
>
a
[
i
]
&
&
d
p
[
i
]
[
0
]
>
d
p
[
i
−
1
]
[
0
]
)
dp[i][0] = dp[i - 1][0],op[i][0] = 0;(a[i - 1] > a[i] \&\& dp[i][0] > dp[i - 1][0])
dp[i][0]=dp[i−1][0],op[i][0]=0;(a[i−1]>a[i]&&dp[i][0]>dp[i−1][0]) 此位接在前位后做降序序列
d
p
[
i
]
[
0
]
=
a
[
i
−
1
]
,
o
p
[
i
]
[
0
]
=
1
;
(
d
p
[
i
−
1
]
[
1
]
>
a
[
i
]
&
&
d
p
[
i
]
[
0
]
>
a
[
i
−
1
]
)
dp[i][0] = a[i - 1],op[i][0] = 1;(dp[i - 1][1] > a[i] \&\& dp[i][0] > a[i - 1])
dp[i][0]=a[i−1],op[i][0]=1;(dp[i−1][1]>a[i]&&dp[i][0]>a[i−1]) 前位做升序序列结尾,此位做降序序列结尾
在上面的两个限制条件中,前一个条件决定了此种情况的可行性,后一个条件决定了做出更新的必要性;
对于dp后的结果,只要 d p [ i ] [ j ] dp[i][j] dp[i][j] 不是初始值,即代表此种情况存在可行解,通过 o p [ i ] [ j ] op[i][j] op[i][j] 标记的方向回溯即可;
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 0x7f7f7f7f;
int a[200005];
int dp[200005][2];
int op[200005][2];
int opt[200005];
int main()
{
int n;
scanf("%d", &n);
for (int i = 1; i <= n; i++)
scanf("%d", &a[i]);
dp[1][1] = inf, dp[1][0] = -inf;
for (int i = 2; i <= n; i++)
{
dp[i][1] = -inf, dp[i][0] = inf;
if (a[i - 1] < a[i] && dp[i][1] < dp[i - 1][1])
{
dp[i][1] = dp[i - 1][1];
op[i][1] = 1;
}
if (dp[i - 1][0] < a[i] && dp[i][1] < a[i - 1])
{
dp[i][1] = a[i - 1];
op[i][1] = 0;
}
if (a[i - 1] > a[i] && dp[i][0] > dp[i - 1][0])
{
dp[i][0] = dp[i - 1][0];
op[i][0] = 0;
}
if (dp[i - 1][1] > a[i] && dp[i][0] > a[i - 1])
{
dp[i][0] = a[i - 1];
op[i][0] = 1;
}
}
if (dp[n][1] != -inf)
{
printf("YES\n");
for (int i = n, optmp = 1; i >= 1; i--)
{
opt[i] = optmp;
optmp = op[i][optmp];
}
for (int i = 1; i <= n; i++)
{
printf("%d ", opt[i] != 1);
}
}
else if (dp[n][0] != inf)
{
printf("YES\n");
for (int i = n, optmp = 0; i >= 1; i--)
{
opt[i] = optmp;
optmp = op[i][optmp];
}
for (int i = 1; i <= n; i++)
{
printf("%d ", opt[i] != 1);
}
}
else
printf("NO");
return 0;
}