【状态机dp 状态压缩 分组】1994. 好子集的数目

本文涉及知识点

动态规划汇总
动态规划 状态机dp 状态压缩 分组

LeetCode1994. 好子集的数目

给你一个整数数组 nums 。如果 nums 的一个子集中,所有元素的乘积可以表示为一个或多个 互不相同的质数 的乘积,那么我们称它为 好子集 。
比方说,如果 nums = [1, 2, 3, 4] :
[2, 3] ,[1, 2, 3] 和 [1, 3] 是 好 子集,乘积分别为 6 = 23 ,6 = 23 和 3 = 3 。
[1, 4] 和 [4] 不是 好 子集,因为乘积分别为 4 = 22 和 4 = 22 。
请你返回 nums 中不同的 好 子集的数目对 109 + 7 取余 的结果。
nums 中的 子集 是通过删除 nums 中一些(可能一个都不删除,也可能全部都删除)元素后剩余元素组成的数组。如果两个子集删除的下标不同,那么它们被视为不同的子集。
示例 1:
输入:nums = [1,2,3,4]
输出:6
解释:好子集为:

  • [1,2]:乘积为 2 ,可以表示为质数 2 的乘积。
  • [1,2,3]:乘积为 6 ,可以表示为互不相同的质数 2 和 3 的乘积。
  • [1,3]:乘积为 3 ,可以表示为质数 3 的乘积。
  • [2]:乘积为 2 ,可以表示为质数 2 的乘积。
  • [2,3]:乘积为 6 ,可以表示为互不相同的质数 2 和 3 的乘积。
  • [3]:乘积为 3 ,可以表示为质数 3 的乘积。
    示例 2:
    输入:nums = [4,2,3,15]
    输出:5
    解释:好子集为:
  • [2]:乘积为 2 ,可以表示为质数 2 的乘积。
  • [2,3]:乘积为 6 ,可以表示为互不相同质数 2 和 3 的乘积。
  • [2,15]:乘积为 30 ,可以表示为互不相同质数 2,3 和 5 的乘积。
  • [3]:乘积为 3 ,可以表示为质数 3 的乘积。
  • [15]:乘积为 15 ,可以表示为互不相同质数 3 和 5 的乘积。

提示:

1 <= nums.length <= 105
1 <= nums[i] <= 30

原理

m = max(nums),最大为30。
一,子集就是子序列。空子序列显然不符合要求。
二,1无法表示成质数相乘,所以乘积为1(全部为1的子序列)的忽略。
三,一二结合,先排除空序列,再处理1。
四,除1外,其它数最多只能选一次。1最后处理,排除空序列后,1可以任意选择。有x个1,就有2x种选法。
五,如果一个数包括两个质因数的平方,则忽略,如:4,8,16。

变量解释

m最大为30,故只需要考虑10个质因数。mask &(1 << i) 表示第i个质因数是否使用。
vPrime 记录前30个质数。
vMask[x] 记录x包括那些质数。
cnt[x] 记录x的个数。
vx记录[2,m]中不包括相同质因子的数。

超时的状态表示

dp[i][j] 表示处理了num前i个元素,j表示质因数的使用情况。空间复杂度:O(n 210) ≈ \approx 108
除一外,每个数字只会选择一次,故只需要考虑x是否被选择,如果被选择,需要数乘以cnt[x],表示可以选择任意一个。

动态规划处理[2,m]

动态规划的状态表示

dp[i][j]表示已经处理了[2,i),正在处理i ,质数使用情况为j的数量。
空间复杂度:O(210m)。

动态规划的转移方程

pre表示dp[i-1],dp表示dp[i]。
i不被选择dp = pre。
枚举前置状态。
如果!(iPre&vMask[x]) 也就两者没有相同的质因数
dp[iPre| vMask[x]] += pre[iPre]*cnt[x];
转移方程时间复杂度:O(1),总时间复杂度:O(210m)

动态规划的初始状态

pre[0]=1,其它全部为0。

动态规划的返回值

auto biRet = std::accumulate(vPre.begin(), vPre.end(), C1097Int(-1));//排除空子集biRet *= C1097Int<>(2).pow(cnt[1]);

动态规划的填表顺序

i从2到m。

代码

vector<int> CreatePrime(int iMax)
{vector<int> vNo(iMax + 1);vector<int> vPrime;for (int i = 2; i <= iMax; i++){		if (!vNo[i]){vPrime.emplace_back(i);}for (const auto& n : vPrime){if( n * i > iMax ){break;}vNo[n * i] = true;}		}return vPrime;
}template<int MOD = 1000000007>
class C1097Int
{
public:C1097Int(long long llData = 0) :m_iData(llData% MOD){}C1097Int  operator+(const C1097Int& o)const{return C1097Int(((long long)m_iData + o.m_iData) % MOD);}C1097Int& operator+=(const C1097Int& o){m_iData = ((long long)m_iData + o.m_iData) % MOD;return *this;}C1097Int& operator-=(const C1097Int& o){m_iData = (m_iData + MOD - o.m_iData) % MOD;return *this;}C1097Int  operator-(const C1097Int& o){return C1097Int((m_iData + MOD - o.m_iData) % MOD);}C1097Int  operator*(const C1097Int& o)const{return((long long)m_iData * o.m_iData) % MOD;}C1097Int& operator*=(const C1097Int& o){m_iData = ((long long)m_iData * o.m_iData) % MOD;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(long long n)const{C1097Int iRet = 1, iCur = *this;while (n){if (n & 1){iRet *= iCur;}iCur *= iCur;n >>= 1;}return iRet;}C1097Int PowNegative1()const{return pow(MOD - 2);}int ToInt()const{return m_iData;}
private:int m_iData = 0;;
};class Solution {
public:int numberOfGoodSubsets(vector<int>& nums) {auto vPrime = CreatePrime(30);const int iMaskCount = 1 << vPrime.size();int vMask[31] = { 0 };for (int i = 1; i <= 30; i++) {for (int j = 0; j < vPrime.size(); j++) {if (0 != i % vPrime[j]) { continue; }vMask[i] |= (1 << j);}}int cnt[31] = { 0 };for (const auto& n : nums) {cnt[n]++;}vector<int> vx;for (int x = 2; x <= 30; x++){bool bNeed = true;for (int j = 0; (j < vPrime.size()) && (vPrime[j] * vPrime[j] <= x);j++) {if (0 == x % (vPrime[j] * vPrime[j])) { bNeed = false; }}if (bNeed) { vx.emplace_back(x); }}vector<C1097Int<>> vPre(iMaskCount);vPre[0] = 1;for (auto x : vx) {vector<C1097Int<>> dp = vPre;for (int iPre = 0; iPre < iMaskCount; iPre++) {if (iPre & vMask[x]) { continue; }//质因数重复dp[iPre | vMask[x]] += vPre[iPre] * cnt[x];}vPre.swap(dp);auto biRet = std::accumulate(vPre.begin(), vPre.end(), C1097Int(-1));//排除空子集std::cout << "x:" << x << " " << biRet.ToInt() << std::endl;}	auto biRet = std::accumulate(vPre.begin(), vPre.end(), C1097Int(-1));//排除空子集biRet *= C1097Int<>(2).pow(cnt[1]);return biRet.ToInt();}
};

测试用例

template<class T>
void Assert(const T& t1, const T& t2)
{assert(t1 == t2);
}template<class T>
void Assert(const vector<T>& v1, const vector<T>& v2)
{if (v1.size() != v2.size()){assert(false);return;}for (int i = 0; i < v1.size(); i++){Assert(v1[i], v2[i]);}}int main()
{vector<int> nums;{Solution sln;nums = { 1,1 };auto res = sln.numberOfGoodSubsets(nums);Assert(0, res);}{Solution sln;nums = { 1,2,3,4 };auto res = sln.numberOfGoodSubsets(nums);Assert(6, res);}{Solution sln;nums = { 4,2,3,15 };auto res = sln.numberOfGoodSubsets(nums);Assert(5, res);}}

扩展阅读

视频课程

有效学习:明确的目标 及时的反馈 拉伸区(难度合适),可以先学简单的课程,请移步CSDN学院,听白银讲师(也就是鄙人)的讲解。
https://edu.csdn.net/course/detail/38771

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

相关下载

想高屋建瓴的学习算法,请下载《喜缺全书算法册》doc版
https://download.csdn.net/download/he_zhidan/88348653

我想对大家说的话
闻缺陷则喜是一个美好的愿望,早发现问题,早修改问题,给老板节约钱。
子墨子言之:事无终始,无务多业。也就是我们常说的专业的人做专业的事。
如果程序是一条龙,那算法就是他的是睛

测试环境

操作系统:win7 开发环境: VS2019 C++17
或者 操作系统:win10 开发环境: VS2022 C++17
如无特殊说明,本算法用**C++**实现。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/5057.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

离散数学之命题逻辑思维导图+大纲笔记(预习、期末复习,考研,)

大纲笔记&#xff1a; 命题逻辑的基本概念 命题与联结词 命题 命题是推理的基本单位 真命题&#xff0c;假命题 特征 陈述句 唯一的真值 是非真即假的陈述句 非命题 疑问句 祈使句 可真可假 悖论 模糊性 三个基本概念 复合命题 真值取决于原子命题的值和逻辑联结词 原子命题 逻…

基于SSM的考研助手系统(有报告)。Javaee项目。ssm项目。

演示视频&#xff1a; 基于SSM的考研助手系统&#xff08;有报告&#xff09;。Javaee项目。ssm项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&#xff0c;通过Spring Spri…

【Java】图书管理系统 介绍与实现

欢迎浏览高耳机的博客 希望我们彼此都有更好的收获 感谢三连支持&#xff01; 1.介绍 图书馆作为知识的殿堂和学术的中心&#xff0c;其管理系统不仅是图书馆管理的必备工具&#xff0c;更是为用户提供优质、高效服务的重要保障&#xff0c;促进了知识的传播和学术的发展。随着…

基于FPGA的数字信号处理(6)--如何确定Verilog表达式的符号

前言 尽管signed语法的使用能带来很多便利&#xff0c;但同时也给表达式的符号确定带来了更多的不确定性。比如一个有符号数和一个无符号数的加法/乘法结果是有符号数还是无符号数&#xff1f;一个有符号数和一个无符号数的比较结果是有符号数还是无符号数&#xff1f;等等。接…

力扣刷题Day2

题目链接&#xff1a; 24. 两两交换链表中的节点 - 力扣&#xff08;LeetCode&#xff09; 效果&#xff1a; 解题思路&#xff1a; 给定一个链表&#xff0c;两两交换其中相邻的节点&#xff0c;并返回交换后的链表。 注意不可以只是单纯的改变节点内部的值&#xff0c;而…

《QT实用小工具·四十七》可交互的创意动态按钮

1、概述 源码放在文章末尾 该项目实现了可交互的创意动态按钮&#xff0c;包含如下功能&#xff1a; 所有颜色自定义 鼠标悬浮渐变 两种点击效果&#xff1a;鼠标点击渐变 / 水波纹动画&#xff08;可多层波纹叠加&#xff09; 额外鼠标移入/移出/按下/弹起的实时/延迟共8种事…

51单片机两个中断及中断嵌套

文章目录 前言一、中断嵌套是什么&#xff1f;二、两个同级别中断2.1 中断运行关系2.2 测试程序 三、两个不同级别中断实现中断嵌套3.1 中断运行关系3.2 测试程序 总结 前言 提示&#xff1a;这里可以添加本文要记录的大概内容&#xff1a; 课程需要&#xff1a; 提示&#x…

德国著名自动化公司Festo设计了一款仿生蜜蜂,仅重34g,支持多只蜜蜂编队飞行!...

德国著名的气动元件研发及自动化解决方案供应商Festo公司近日展示了一款仿生蜜蜂&#xff08;BionicBee&#xff09;&#xff0c;重量只有34g&#xff0c;却完全可以实现自主飞行&#xff0c;还支持多只相同的蜜蜂机器人编队飞行。 BionicBee 重约 34 克&#xff0c;长 22 厘米…

Redis线程模型及性能优化概述

redis线程模型&#xff1a; 网络模块命令处理 redis的性能&#xff1a; 一个取决于物理内存&#xff0c;另一个是对于socket请求的处理速度。 4.0以前 单线程模式 请求流程&#xff1a;对于一个请求&#xff0c;线程会根据操作产生相应的事件&#xff08;读&#xff0c;写事…

基于Springboot的水产养殖系统(有报告)。Javaee项目,springboot项目。

演示视频&#xff1a; 基于Springboot的水产养殖系统&#xff08;有报告&#xff09;。Javaee项目&#xff0c;springboot项目。 项目介绍&#xff1a; 采用M&#xff08;model&#xff09;V&#xff08;view&#xff09;C&#xff08;controller&#xff09;三层体系结构&…

【MyBatis】进阶使用 (动态SQL)

动态SQL \<if>\<trim>\<where>\<set>\<foreach>\<include> 在填写表单时&#xff0c;有些数据是非必填字段&#xff08;例如性别&#xff0c;年龄等字段&#xff09;&#xff0c;那就需要在接收到参数时判断&#xff0c;根据参数具体的情况…

【知识学习/复习】损失函数篇,包含理解应用与分类:回归、分类、排序、生成等任务

损失函数总结 一、损失函数理解二、不同任务的损失函数的应用1.图像分类2.目标检测3.语义分割4.自然语言处理&#xff08;NLP&#xff09;5.图神经网络&#xff08;GNN&#xff09;6.生成式网络 三、损失函数1. 回归任务损失函数常见损失函数IoU系列损失函数1. IoU损失函数&…

TiDB 利用binlog 恢复-反解析binlog

我们知道TiDB的binlog记录了所有已经执行成功的dml语句&#xff0c;类似mysql binlog row模式 &#xff0c;TiDB官方也提供了reparo可以进行解析binlog&#xff0c;如下所示: [2024/04/26 20:58:02.136 08:00] [INFO] [config.go:153] ["Parsed start TSO"] [ts449…

[C++][数据结构]二叉搜索树:介绍和实现

二叉搜索树 概念 二叉搜索树又称二叉排序树&#xff0c;它是一棵空树&#xff0c;或者是具有以下性质的二叉树: 若它的左子树不为空&#xff0c;则左子树上所有节点的值都小于根节点的值若它的右子树不为空&#xff0c;则右子树上所有节点的值都大于根节点的值它的左右子树也…

IoT Scenario: Smart Retail System-Multiple Sources and Multiple Terminals

物联网/大数据可视化领域发文可以联系&#xff1a;nascimsina.com IoT Scenario: Smart Retail System Overview The use of IoT in the retail industry enhances customer experiences, optimizes inventory management, and provides valuable insights into consumer beh…

【架构】后端项目如何分层及分层领域模型简化

文章目录 一. 如何分层1. 阿里规范2. 具体案例分析 二. 分层领域模型的转换1. 阿里规范2. 模型种类简化分析 三. 小结 本文描述后端项目中如何进行分层&#xff0c;以及分层领域模型简化 一. 如何分层 1. 阿里规范 阿里的编码规范中约束分层逻辑如下: 开放接口层&#xff1a…

Java全栈开发前端+后端(全栈工程师进阶之路)-环境搭建

在课程开始前我们要配置好我们的开发环境&#xff0c;这里我的电脑太乱了&#xff0c;我使用vm虚拟机进行搭建开发环境&#xff0c;如果有需要环境的或者安装包&#xff0c;可以私信我。 那我们开始 首先我们安装数据库 这里我们使用小皮面板 小皮面板(phpstudy) - 让天下没…

【计算机毕业设计】基于SSM++jsp的社区管理与服务系统【源码+lw+部署文档+讲解】

目录 摘 要 Abstract 第一章 绪论 第二章 系统关键技术 第三章 系统分析 3.1.1技术可行性 3.1.2经济可行性 3.1.3运行可行性 3.1.4法律可行性 3.4.1注册流程 3.4.2登录流程 3.4.3活动报名流程 第四章 系统设计 4.3.1登录模块顺序图 4.3.2添加信息模块顺序图 4.4.1 数据库E-…

【Node.js工程师养成计划】之express框架

一、Express 官网&#xff1a;http://www.expressjs.com.cn express 是一个基于内置核心 http 模块的&#xff0c;一个第三方的包&#xff0c;专注于 web 服务器的构建。 Express 是一个简洁而灵活的 node.js Web应用框架, 提供了一系列强大特性帮助你创建各种 Web 应用&…

使用LocalGPT+cpolar打造可远程访问的本地私有类chatgpt服务

文章目录 前言环境准备1. localGPT部署2. 启动和使用3. 安装cpolar 内网穿透4. 创建公网地址5. 公网地址访问6. 固定公网地址 前言 本文主要介绍如何本地部署LocalGPT并实现远程访问&#xff0c;由于localGPT只能通过本地局域网IP地址端口号的形式访问&#xff0c;实现远程访问…