【状态机动态规划】3686. 稳定子序列的数量|1969

本文涉及知识点

C++动态规划

3686. 稳定子序列的数量

给你一个整数数组 nums。

如果一个 子序列 中 不存在连续三个 元素奇偶性相同(仅考虑该子序列内),则称该子序列为稳定子序列 。

请返回所有稳定子序列的数量。

由于结果可能非常大,请将答案对 109 + 7 取余数后返回。

子序列 是一个从数组中通过删除某些元素(或不删除任何元素),并保持剩余元素相对顺序不变的 非空 数组。

示例 1:

输入: nums = [1,3,5]

输出: 6

解释:

稳定子序列为:[1], [3], [5], [1, 3], [1, 5], 和 [3, 5]。

子序列 [1, 3, 5] 不稳定,因为它包含三个连续的奇数。因此答案是 6。

示例 2:

输入: nums = [2,3,4,2]

输出: 14

解释:

唯一一个不稳定子序列是 [2, 4, 2],因为它包含三个连续的偶数。

所有其他子序列都是稳定子序列。因此答案是 14。

提示:

1 <= nums.length <= 105

1 <= nums[i] <= 105

动态规划

动态规划的状态表示

dp[n][m1][m2],n表示已经处理了nums长度为n的前缀,m2表示此子序列最后一个数字是否是奇数,m1表示奇偶性相同的最长后缀。 0 ≤ m 1 < 3 , 0 ≤ m 2 < 2 0 \le m1 <3,0\le m2 <2 0≤m1<3,0≤m2<2。

利用滚动向量优化空间,pre=dp[n],cur=dp[n+1]。优化后,空间复杂度:O(1)。

动态规划的填报顺序

枚举前驱状态,和选择。选取当前数字,不选取当前数字。

动态规划的转移方程

处理不选取当前数字: cur =pre。

前驱状态m2 当前数是否奇数 后续状态
true true cur[m1+1][m2]
true false cur[1][0]
false true cur[1][1]
false false cur[m1+1][m2]

动态规划的初始值

pre[0][0]=1

动态规划的返回值

∑ p r e \sum pre ∑pre -1。排除空串。

代码

核心代码

cpp 复制代码
template<long long MOD = 1000000007,class T1 = int, class T2 = long long>
class C1097Int
{
public:
	C1097Int(T1 iData = 0) :m_iData(iData% MOD)
	{

	}
	C1097Int(T2 llData) :m_iData(llData% MOD) {

	}
	C1097Int  operator+(const C1097Int& o)const
	{
		return C1097Int(((T2)m_iData + o.m_iData) % MOD);
	}
	C1097Int& operator+=(const C1097Int& o)
	{
		m_iData = ((T2)m_iData + o.m_iData) % MOD;
		return *this;
	}
	C1097Int& operator-=(const C1097Int& o)
	{
		m_iData = ((T2)MOD + m_iData - o.m_iData) % MOD;
		return *this;
	}
	C1097Int  operator-(const C1097Int& o)const
	{
		return C1097Int(((T2)MOD + m_iData - o.m_iData) % MOD);
	}
	C1097Int  operator*(const C1097Int& o)const
	{
		return((T2)m_iData * o.m_iData) % MOD;
	}
	C1097Int& operator*=(const C1097Int& o)
	{
		m_iData = ((T2)m_iData * o.m_iData) % MOD;
		return *this;
	}
	C1097Int  operator/(const C1097Int& o)const
	{
		return *this * o.PowNegative1();
	}
	C1097Int& operator/=(const C1097Int& o)
	{
		*this *= o.PowNegative1();
		return *this;
	}
	bool operator==(const C1097Int& o)const
	{
		return m_iData == o.m_iData;
	}
	bool operator<(const C1097Int& o)const
	{
		return m_iData < o.m_iData;
	}
	C1097Int pow(T2 n)const
	{
		C1097Int iRet = (T1)1, iCur = *this;
		while (n)
		{
			if (n & 1)
			{
				iRet *= iCur;
			}
			iCur *= iCur;
			n >>= 1;
		}
		return iRet;
	}
	C1097Int PowNegative1()const
	{
		return pow(MOD - 2);
	}
	T1 ToInt()const
	{
		return ((T2)m_iData + MOD) % MOD;
	}
private:
	T1 m_iData = 0;;
};


class Solution {
		public:
			int countStableSubsequences(vector<int>& nums) {
				vector<vector<C1097Int<>>> pre(3, vector<C1097Int<>>(2));
				pre[0][0] = 1;
				for (const auto& n : nums)
				{
					auto cur = pre;
					for (int i = 0;i < 3;i++) {
						for (int j = 0;j < 2; j++) {
							if (n & 1) {
								if (0 == j) {
									cur[1][1] += pre[i][j];
								}
								else {
									if (i < 2) {
										cur[i + 1][1] += pre[i][j];
									}
								}
							}
							else {
								if (1 == j) {
									cur[1][0] += pre[i][j];
								}
								else if (i < 2) {
									cur[i + 1][0] += pre[i][j];
								}
							}
						}
					}
					pre.swap(cur);
				}
				C1097Int<> ans(-1);
				for (const auto& v : pre) {
					ans += accumulate(v.begin(), v.end(), C1097Int<>(0));
				}
				return ans.ToInt();
			}
		};

单元测试

cpp 复制代码
	vector<int> nums;
	public:
		TEST_METHOD(TestMethod11)
		{
			nums = { 1, 3, 5 };	
			auto res = Solution().countStableSubsequences(nums);
			AssertEx(6, res);
		}
		TEST_METHOD(TestMethod12)
		{
			nums = { 2,3,4,2 };
			auto res = Solution().countStableSubsequences(nums);
			AssertEx(14, res);
		}

扩展阅读

我想对大家说的话
工作中遇到的问题,可以按类别查阅鄙人的算法文章,请点击《算法与数据汇总》。
学习算法:按章节学习《喜缺全书算法册》,大量的题目和测试用例,打包下载。重视操作
有效学习:明确的目标 及时的反馈 拉伸区(难度合适) 专注
员工说:技术至上,老板不信;投资人的代表说:技术至上,老板会信。
闻缺陷则喜(喜缺)是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛
失败+反思=成功 成功+反思=成功

视频课程

先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

如何你想快速形成战斗了,为老板分忧,请学习C#入职培训、C++入职培训等课程
https://edu.csdn.net/lecturer/6176

测试环境

操作系统:win7 开发环境: VS2019 C++17

或者 操作系统:win10 开发环境: VS2022 C++17

如无特殊说明,本算法 用**C++**实现。

相关推荐
森G1 小时前
七、04ledc-sdk--------makefile有变化
linux·c语言·arm开发·c++·ubuntu
驱动探索者1 小时前
linux mailbox 学习
linux·学习·算法
ringking1231 小时前
autoware-1:安装环境cuda/cudnn/tensorRT库函数的判断
人工智能·算法·机器学习
大闲在人2 小时前
8. 供应链与制造过程术语:产能
算法·制造·供应链管理·智能制造·工业工程
橘颂TA2 小时前
【测试】高效浏览器操作:基础功能与优化设置大全
c++·功能测试·职场和发展·测试·web测试
一只小小的芙厨2 小时前
寒假集训笔记·以点为对象的树形DP
c++·算法
历程里程碑2 小时前
普通数组----合并区间
java·数据结构·python·算法·leetcode·职场和发展·tornado
艾莉丝努力练剑2 小时前
hixl vs NCCL:昇腾生态通信库的独特优势分析
运维·c++·人工智能·cann
执风挽^2 小时前
Python基础编程题2
开发语言·python·算法·visual studio code
我在人间贩卖青春2 小时前
C++之new和delete
c++·delete·new