AcWing
  • 首页
  • 课程
  • 题库
  • 更多
    • 竞赛
    • 题解
    • 分享
    • 问答
    • 应用
    • 校园
  • 关闭
    历史记录
    清除记录
    猜你想搜
    AcWing热点
  • App
  • 登录/注册

AcWing 1014. 登山【状态机模型解决最长子序列问题】    原题链接    简单

作者: 作者的头像   一只野生彩色铅笔 ,  2021-05-30 15:33:49 ,  所有人可见 ,  阅读 5831


132


43

最近在补全提高课所有题目的题解,宣传一下汇总的地方提高课题解补全计划

题目描述

题目给定一个长度为 $n$ 的数组 $a[n]$,表示某个景点的海拔高度

观光队从起点出发,初始海拔高度为 $0$,先上山后下山,且开始下山后不再往上走

让我们找出一个方案,使得观光队浏览到的景点数量最多

题解

此题和上题 AcWing 1017. 怪盗基德的滑翔翼 有着异曲同工之妙

上题求的是从一个点开始,朝向一个方向求一个最长下降子序列

本题则是让我们求一个先上升后下降的最长子序列,具体如下图所示

IMG_67CBC7A02142-1.jpeg

当然也和上题一样存在边界情况,即最优解答案可以是一个单调下降子序列或单调上升子序列

这种边界情况一样是先上升后下降的最长子序列的子集,因此不用额外讨论


一种做法是和上题一样,先做一遍最长上升,再做一遍最长下降

然后根据状态表示的特性,将两个状态的值相加,取一个 $\mathrm{Max}$ 就是 先上升后下降的最长子序列的长度

具体代码,以及DP模型的详细分析,参照这篇博客即可 AcWing 1017. 怪盗基德的滑翔翼

我这里给一个不同的思路

这是我做过 AcWing第二场热身赛的C题——AcWing 3549. 最长非递减子序列 后总结出来的一类模型

那就是,利用状态机模型DP解决最长xxx子序列模型的方法

xxx可以是先上升后下降,或者先上升后下降再上升,或者先上升后下降再上升再下降 ···

回到本题,我们就可以先利用状态机模型进行分析,具体如下:

IMG_375680990BCC-1.jpeg

对于本题来说,当前状态如果是上升状态,则他下一个阶段可以维持上升状态,或者变成下降状态

而对于已经处于下降状态来说的状态,下一个阶段只能继续维持下降状态

于是我们便可以写出状态机模型的闫氏DP分析法:

闫氏DP分析法

$$ \begin{cases} 状态表示f_{i,j} \begin{cases} 集合: 以第i个位置作为当前子序列的右端点,且当前状态为j \\\ 属性: 方案的子序列长度最大 Max \end{cases} \\\ 状态转移 \begin{cases} f_{i,0} = max\{\sum f_{k,0}\}+1 \\\ f_{i,1} = max\{\sum f_{k,0}, \sum f_{k,1}\} + 1 \end{cases} \end{cases} $$

初始状态: f[0][0]和f[0][1]

目标状态: f[i][0]和f[i][1]

大家想更近一步了解这类模型的话,可以做一下这道题 AcWing 3549. 最长非递减子序列

Code

#include <iostream>

using namespace std;

const int N = 1010;

int n;
int a[N];
int f[N][2];

int main()
{
    //input
    cin >> n;
    for (int i = 1; i <= n; ++ i) cin >> a[i];

    //dp
    for (int i = 1; i <= n; ++ i)
    {
        f[i][0] = f[i][1] = 1;
        for (int k = 1; k < i; ++ k)
        {
            if (a[k] < a[i]) f[i][0] = max(f[i][0], f[k][0] + 1);
            if (a[k] > a[i]) f[i][1] = max(f[i][1], max(f[k][0], f[k][1]) + 1);
        }
    }

    //find result from all final states
    int res = 0;
    for (int i = 1; i <= n; ++ i) res = max(res, max(f[i][0], f[i][1]));
    cout << res << endl;

    return 0;
}

30 评论


用户头像
Hanasaki   2021-07-31 11:22      3    踩      回复

学长写的文章太好了呜呜

用户头像
一只野生彩色铅笔   2021-07-31 12:09      2    踩      回复

QwQ


用户头像
谁把可乐的名字拿走了   2022-09-18 17:54      1    踩      回复

大佬大佬tql


用户头像
lniks   2025-05-19 14:37 · 广东         踩      回复

🐂


用户头像
秧歌star   2024-04-12 18:56         踩      回复

我写dp题发现状态机经常用


用户头像
秧歌star   2024-04-12 18:55         踩      回复

6


用户头像
秧歌star   2023-12-31 17:28         踩      回复

#include[HTML_REMOVED]
#include[HTML_REMOVED]
#include[HTML_REMOVED]

using namespace std;

const int N = 1010;

int n,h[N],up[N],down[N],tt=-1,hh=0, q[N];

int find(int x)
{
int l = hh, r = tt;
while(l < r)
{
int mid = (l + r) / 2;
if(q[mid] >= x) r = mid;
else l = mid + 1;
}
return l;
}

int main()
{
ios::sync_with_stdio(false);
cin>>n;
for(int i = 0; i < n; i++) cin >> h[i];

q[++tt] = h[0];
up[0] = tt;
for(int i = 1; i < n; i++)
{    
    if(h[i] > q[tt]) q[++tt] = h[i];
    else q[find(h[i])] = h[i];
    up[i] = tt;
}
tt = -1,hh = 0;
q[++tt] = h[n -1];
down[n-1] = tt;
for(int i = n -2; i >= 0; i--)
{
    if(h[i] > q[tt]) q[++tt] = h[i];
    else q[find(h[i])] = h[i];
    down[i] = tt;
}

int res = 0;
for(int i = 0; i < n; i++) 
    res = max(res,up[i] + down[i] + 1);

cout<<res;

return 0;

}

感觉是不是贪心才是尽头》》》2分加贪心


用户头像
Aurora0915   2022-09-13 13:44         踩      回复

大佬Orz !!!


用户头像
TreeTraveler   2022-08-02 20:43         踩      回复

请问dp转移的过程中为什么不需要考虑a[k] = a[i] 的情况?

用户头像
糖豆   2023-05-06 13:57         踩      回复

题目中说了:不连续浏览海拔相同的两个景点


用户头像
一只猫咪不加糖   2022-06-09 15:50         踩      回复

您好 请问 处于下降状态之后 就无法再转换到上升状态 是如何体现的呢?

用户头像
旦驳   2023-03-12 12:36         踩      回复

通过对f[i][0]和f[i][1]的不同赋值实现的。


用户头像
Verse   2022-05-10 16:28         踩      回复

Orz


用户头像
Lucius7   2022-04-04 14:52         踩      回复

有个问题 :
https://www.acwing.com/community/content/874203/


用户头像
灰原乐   2022-03-31 21:04         踩      回复

绝杀绝杀绝杀绝杀


用户头像
我是憨憨一号   2021-10-26 20:14         踩      回复

这思路 绝杀!


用户头像
Laurus_1   2021-09-21 22:18         踩      回复

第二维0 1 分别代表啥状态啊

用户头像
一只野生彩色铅笔   2021-09-21 22:26         踩      回复

0:上升
1:下降


用户头像
鸢一折纸   2021-08-26 19:59         踩      回复

卧槽,彩笔牛逼


用户头像
新.一   2021-06-03 15:39         踩      回复

大佬太强了

用户头像
一只野生彩色铅笔   2021-06-03 15:42         踩      回复

%%

用户头像
新.一   2021-06-03 16:00    回复了 一只野生彩色铅笔 的评论         踩      回复

有个疑问 这句是什么意思 max(f[i][0], f[i][1])

用户头像
一只野生彩色铅笔   2021-06-03 16:09    回复了 新.一 的评论         踩      回复

最终的答案不一定是先上升后下降,有可能只上升,所以要在两个状态里取一个max


用户头像
代码搬运工   2021-06-03 10:53         踩      回复

tql

用户头像
一只野生彩色铅笔   2021-06-03 11:22         踩      回复

%%


用户头像
迷弟   2021-05-31 13:35         踩      回复

话说你赞完了又取消了么0-0 这个

用户头像
一只野生彩色铅笔   2021-05-31 13:41         踩      回复

没有取消,看样子是有人点了个踩

用户头像
迷弟   2021-05-31 15:08    回复了 一只野生彩色铅笔 的评论         踩      回复

。可恶

用户头像
迷弟   2021-06-01 10:48         踩      回复

话说你这头像好高清0=0

用户头像
一只野生彩色铅笔   2021-06-01 11:23    回复了 迷弟 的评论         踩      回复

那肯定不及 烟火 卤蛋 烟火 ww


App 内打开
你确定删除吗?
1024
x

© 2018-2025 AcWing 版权所有  |  京ICP备2021015969号-2
用户协议  |  隐私政策  |  常见问题  |  联系我们
AcWing
请输入登录信息
更多登录方式: 微信图标 qq图标 qq图标
请输入绑定的邮箱地址
请输入注册信息