线性dp-LIS题目4(A Twisty Movement)

题目链接

1 解题思路

1.1 没有翻转的情况

这道题我们先思考一下,如果没有翻转这个条件的情况。这时,我们可以拆分成两种情况,一种是最长不下降子序列只有1,另一种是最长不下降子序列有1也可以有2,如果当前的数字 a i ai ai是1就只能接在第一种情况后面;如果当前数字 a i ai ai是2,可以接在最长不下降子序列有1也可以有2的序列后面。

我们记最长不下降子序列只有1的子序列长度为 d p 1 i dp1i dp1i,最长不下降子序列有1也有2的子序列长度为 d p 2 i dp2i dp2i。初始化所有 d p 1 dp1 dp1和 d p 2 dp2 dp2的元素为1,只有自己时,长度为1。

得到状态转移方程: d p 1 i = d p 1 i − 1 + ( a i = = 1 ) dp1i=dp1i-1+(ai==1) dp1i=dp1i−1+(ai==1), d p 2 i = m a x ( d p 1 i , d p 2 i − 1 + ( a i = = 2 ) ) dp2i=max(dp1i,dp2i-1+(ai==2)) dp2i=max(dp1i,dp2i−1+(ai==2))

注意: 在这里 d p 2 dp2 dp2不是必须接2,可能比较容易错写成: d p 2 i = m a x ( d p 1 i , d p 2 i − 1 ) + ( a i = = 2 ) dp2i=max(dp1i,dp2i-1)+(ai==2) dp2i=max(dp1i,dp2i−1)+(ai==2)。这里蕴含了贪心的思想。如果dp1的纯1序列长度比dp2长,后面再来 1 或者 2 都能合法接上,选择自由度最高。如果这时还要硬选2,按照不下降规则,末尾是 2 之后再也不能接 1,一旦后面出现 1,这条路线直接 "走死",灵活性极低。所以, d p 2 i dp2i dp2i的可以允许有2,但也可以不选2。最后,输出答案 d p 2 n dp2n dp2n。

1.2 加入翻转的情况

如果加入翻转,我们再定义一个 d p 3 dp3 dp3, d p 3 dp3 dp3的更新在更新完 d p 2 dp2 dp2之后。一般来说,遇到 a i = 1 ai=1 ai=1的时候会反转,故 d p 3 i = m a x ( d p 2 i , d p 3 i − 1 + ( a i = = 1 ) ) dp3i=max(dp2i,dp3i-1+(ai==1)) dp3i=max(dp2i,dp3i−1+(ai==1)),同样也是贪心的思想,如果 d p 2 dp2 dp2长度更长,就不浪费这次翻转机会,后续元素要反转可以在 d p 2 dp2 dp2指向的子序列后面。如果 a i = 1 ai=1 ai=1且 d p 3 i − 1 + 1 dp3i-1+1 dp3i−1+1更大,这样意味着翻转区间右端点延长到 i i i这样得到的不下降子序列更长,那选择翻转。翻转区间左端点在有1也有2的序列里面,一般是第一个在2之后出现的1所在的下标。所以 d p 3 dp3 dp3的主要作用是看右区间是不是要延展到 i i i。

翻转之后,后面的元素可以接在最长不下降序列后面,比如翻转后如果当前元素 a i = 2 ai=2 ai=2,就可以接上去。如果 a i = 1 ai=1 ai=1,如果最长不下降序列全是1,那 d p 1 dp1 dp1那里已经累计过了,会继承到 d p 3 dp3 dp3;如果最长不下降子序列有1也有2,那么翻转后的最长不下降子序列最后一个是2,接不上。故我们再开一个 d p 4 dp4 dp4, d p i = m a x ( d p 3 i , d p 4 i − 1 + ( a i = = 2 ) ) dpi=max(dp3i,dp4i-1+(ai==2)) dpi=max(dp3i,dp4i−1+(ai==2))。最后答案输出 d p 4 n dp4n dp4n。

更新的核心代码

bash 复制代码
for(int i=1;i<=n;i++){
	dp1[i]=dp1[i-1]+(a[i]==1);
    dp2[i]=max(dp1[i],dp2[i-1]+(a[i]==2));
    dp3[i]=max(dp2[i],dp3[i-1]+(a[i]==1));
    dp4[i]=max(dp3[i],dp4[i-1]+(a[i]==2));
}
1.3 空间复杂度优化

由于 d p dp dp值的更新只有上一次有关,和前面的无关,我们实际上可以用一个 d p dp dp数组存储, d p 0 dp0 dp0, d p 1 dp1 dp1, d p 2 dp2 dp2, d p 3 dp3 dp3分别存原来 d p 1 i dp1i dp1i, d p 2 i dp2i dp2i, d p 3 i dp3i dp3i, d p 4 i dp4i dp4i的值。这样空间复杂度就大大优化了。

2 AC Code

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
int n,x,dp[4];
int main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		cin>>x;
		dp[0]=dp[0]+(x==1);
		dp[1]=max(dp[0],dp[1]+(x==2));
		dp[2]=max(dp[1],dp[2]+(x==1));
		dp[3]=max(dp[2],dp[3]+(x==2));
	}
	cout<<dp[3];
  return 0;
}

总结: 这题很锻炼思维。

相关推荐
東隅已逝,桑榆非晚1 小时前
算法2. 双指针法-复写零
c++·笔记·学习·算法
云析赢指标公式网42 小时前
文华财经指标源码笔记:WINNER筹码函数、控盘变量与MACD变体的调试记录
java·笔记·算法
CC数分3 小时前
统计学基础|先把问题问对:数据分析的六大类型
大数据·人工智能·算法
地平线开发者4 小时前
CLIP 的训练机制:从对比学习到图文对齐
深度学习·算法·自动驾驶
hetao17338374 小时前
2026-11-02 hetao1733837 的刷题记录
c++·算法
Geektec4 小时前
IMU 选型完全指南:从硬件参数到算法融合的系统工程视角
算法·imu·陀螺仪·加速度计·元器件选型
CQU_JIAKE4 小时前
11.2【A】
算法
Godspeed Zhao5 小时前
从零开始学AI21——决策树
算法·决策树·机器学习
开开心心就好5 小时前
网页图片批量下载工具,输入链接就保存
服务器·算法·leetcode·支持向量机·pdf·ocr·1024程序员节
Navigator_Z6 小时前
LeetCode //C - 1313. Decompress Run-Length Encoded List
c语言·算法·leetcode