Two Merged Sequences(CF 1144 G)(将序列拆分成升序序列和降序序列两部分)-DP

题目链接
参考

思路

构建状态表示:
dp[i][1]dp[i][1] 代表在前 i 位中,若第 i 位为升序序列结尾,此时降序序列结尾的最大值;
op[i][1]op[i][1] 代表若第 i 位为升序序列结尾,dp[i][1]dp[i][1]取当前值时,第 i-1 位在升序序列 / 降序序列(1升0降);
dp[i][0]dp[i][0] 代表在前 i 位中,若第 i 位为降序序列结尾,此时升序序列结尾的最小值;
op[i][0]op[i][0] 代表若第 i 位为降序序列结尾,dp[i][0]dp[i][0]取当前值时,第 i-1 位在升序序列 / 降序序列(1升0降);

定义初值:
dp[i][1]=inf,dp[i][1]=infdp[i][1]=-inf,dp[i][1]=inf 即每一位默认是不能参与序列的,直至转移方程时满足条件才可更新;
特殊地, dp[1][1]=inf,dp[1][0]=infdp[1][1]=inf,dp[1][0]=-inf 即第一位既可以在升序序列,也可以在降序序列;

状态转移方程:
dp[i][1]=dp[i1][1],op[i][1]=1;(a[i1]<a[i]&&dp[i][1]<dp[i1][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]=a[i1],op[i][1]=0;(dp[i1][0]<a[i]&&dp[i][1]<a[i1])dp[i][1] = a[i - 1],op[i][1] = 0;(dp[i - 1][0] < a[i] \&\& dp[i][1] < a[i - 1]) 前位做降序序列结尾,此位做升序序列结尾
dp[i][0]=dp[i1][0],op[i][0]=0;(a[i1]>a[i]&&dp[i][0]>dp[i1][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]=a[i1],op[i][0]=1;(dp[i1][1]>a[i]&&dp[i][0]>a[i1])dp[i][0] = a[i - 1],op[i][0] = 1;(dp[i - 1][1] > a[i] \&\& dp[i][0] > a[i - 1]) 前位做升序序列结尾,此位做降序序列结尾
在上面的两个限制条件中,前一个条件决定了此种情况的可行性,后一个条件决定了做出更新的必要性;

对于dp后的结果,只要 dp[i][j]dp[i][j] 不是初始值,即代表此种情况存在可行解,通过 op[i][j]op[i][j] 标记的方向回溯即可;

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#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;
}


Two Merged Sequences(CF 1144 G)(将序列拆分成升序序列和降序序列两部分)-DP
https://tanyuu.github.io/2022.01-06/Two Merged Sequences(CF 1144 G)(将序列拆分成升序序列和降序序列两部分)-DP/
作者
F Juny
发布于
2022年6月7日
许可协议