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

题目链接
参考

思路

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

对于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;
}

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值