排列组合初步

什么是排列组合

排列组合是计数问题,顺序不同且值相同算两种方案是排列,顺序不同且值相同算一种方案是组合。

暴力枚举方案能算出方案数,太耗时,运用加法原理和乘法原理可降低时间复杂度。先将原问题拆解成子问题,根据子问题间的关系确定用加法原理还是乘法原理来合并问题的解,求出原问题的解。

计数问题的关键是不重复不遗漏,加法原理和乘法原理是计数问题的重要思想。

很多算法都有拆解(划分)子问题的思想,拆解子问题可简化原问题,方便求解。

暴力枚举是算法的基础,算法是为了优化时间或空间,或着解决用枚举求解起来复杂的问题。

加法原理

本质是求和。子问题间独立,每个子问题计数的都是有几个方案,都已达成目标,那么累加子问题的解。这就是加法原理。

乘法原理

本质是总数 = 每份数×份数。

子问题间不独立,每个子问题都是完整方案的一步,未达到目标。

设当前子问题有x个方法,这x个方法可配之前子问题的方法,如下图,x是份数,之前子问题的方法数是每份数,相乘得解。

排列数

P(n, m) 是排列数,表示n个中选m个的方案数,P(n, m) = n × (n - 1) × (n - 2) ×....× (n - m + 1),如下图。

组合数

C(n, m)表示n个中取m个的组合数,明确排列数和组合数的区别,组合数可由排列数求出,需去重。排列数里方案是相同值不同顺序的算多个,但在组合数里算一个。

用除法去重,总数:P(n, m),每份数:值同顺序不同的排列即P(m, m),求份数。

关键是理解排列数公式、组合数公式的本质,排列数公式、组合数的公式由排列组合的性质得出。

组合数与杨辉三角

组合数和杨辉三角对应,杨辉三角的规律可应用于组合数。

如何对应

如下图,行起始和列起始为0时,vct[i][j] = C(i, j)

杨辉三角规律得出组合数定理

1. vct[i][j] = vct[i - 1][j - 1] + vct[i - 1][j],即C(i, j) = C(i - 1, j - 1) + C(i - 1, j)。

通过递推理解,到第j个有两个决策,选或不选,选:i - 1的部分选j - 1个,不选:i - 1的部分选j个,如下图。

2. 2^i = vct[i][0] + vct[i][1] + vct[i][2] +...+ vct[i][i] = C(i, 0) + C(i, 1) + C(i, 2) +...+ C(i, i)

结合组合数的意义和二进制数理解,C(i, j)(0 <= j <= i)想从i为二进制里取j个1有几种取法,用二进制数表示[0, 2^i - 1],共2^i个数,所以等于2^i。

3.vct[i][i] + vct[i + 1][i] + vct[i + 2][i] +...+ vct[i + k][i] = vct[i + k + 1][i + 1],即C(i, i) + C(i + 1, i) + C(i + 2, i) +...+ C(i + k, i) = C(i + k + 1, i + 1)

公式的图如下:

杨辉三角递推理解如下图:

还可用组合数递推理解。

4.还有一个,待会儿再写

题目

洛谷 B4031 [语言月赛 202409] 始终

B4031 [语言月赛 202409] 始终 - 洛谷

暴力枚举所有“好的”字符串同时计数,若子串不连续,暴力枚举会超时。

#include <iostream>
#include <string>
#include <cmath>
using namespace std;typedef long long LL;int main() {ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);string str;cin >> str;LL res = 0;for (LL i = 0; i < str.size(); ++i) {for (LL j = i; j < str.size(); ++j) {if (str[i] == str[j])  ++res;}}cout << res;return 0;
}

洛谷 P1358 扑克牌

P1358 扑克牌 - 洛谷

每个人拿完牌后当前方案还未完成,是乘法原理。

当前方案每张牌只能出现一次,第i人不能拿第[1, i -1]人拿的num张牌,第i人是在n - num中选ai张牌,值同顺序不同算一种方案,是组合数。

#include <iostream>
#include <cmath>
using namespace std;typedef long long LL;const LL Mo = 10007;LL f_pow(LL a, LL p) {LL ans = 1, b = (a % Mo);while (p > 0) {if ((p & 1) != 0)  ans = (ans * b) % Mo;b = (b * b) % Mo;p >>= 1;}return ans;
}LL C(LL n, LL m) {LL num1 = 1, num2 = 1;for (LL i = 1; i <= m; ++i) {num1 = (num1 * (n - i + 1)) % Mo;num2 = (num2 * i) % Mo;}return (num1 * f_pow(num2, Mo - 2)) % Mo;
}int main() {ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);LL n, m, a;cin >> n >> m;LL num = n, res = 1;for (LL i = 1; i <= m; ++i) {cin >> a;res = (res * C(num, a)) % Mo;num -= a;}cout << res;return 0;
}

洛谷 B4185 倍数子串/子串

B4185 [中山市赛 2024/科大国创杯小学组 2023] 倍数子串/子串 - 洛谷

一个整数,末两位能被4整除,是4的倍数,最后一位是0或5,是5的倍数。

若一个长度≤2的子串,是4的倍数或5的倍数,可和之前任意连续子串组合成4或5的倍数,用乘法原理,x × 1 = x,所以最后直接加没有乘。

既是4的倍数又是5的倍数,4的倍数的情况不计算,5的倍数的情况计算,避免重复,得出的答案正确,若改成4的倍数的情况计算,5的倍数的情况不计算,会漏算[i, i]子串(此时str[i]不是4的倍数不会被记录)。

#include <iostream>
#include <string>
#include <algorithm>
using namespace std;typedef long long LL;int main() {ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);string str;cin >> str;LL res = 0;for (LL i = 0; i < str.size(); ++i) {if (str[i] == '0' || str[i] == '5')  res += i + 1;else {if ((static_cast<LL> (str[i] - '0')) % 4 == 0)  ++res;if (i > 0 && (static_cast<LL> (str[i - 1] - '0') * 10 + static_cast<LL> (str[i] - '0')) % 4 == 0)  res += i;}}cout << res;return 0;
}

2024年12月月赛 丙组 T5 查找404

上海市计算机学会竞赛平台 | YACS

先考虑无“*”:

  • 方案总数:任意4可和前面的所有40组成404,乘法原理,只有一个4,是×1,res加num40。
  • 40个数:4和0不连续,任意0可和前面的4组成40,若当前为0,num40加num4即可。

考虑“*”:

当前是“*”, res、num40、num4需×2。

“*”有两种状态,每个当前已产生的字符串可分出两个字符串,所以需翻倍,每次num4 += p(p记录翻了几倍,当前所有字符串都包含4,所以+=p)。
此时num4、num40为所有字符串的40和4的个数,res为结果。

#include <iostream>
#include <string>
#include <cmath>
using namespace std;typedef long long LL;const LL Mo = 1e9 + 7;int main() {ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);LL t, n;string str;cin >> t;LL res = 0, num4 = 0, num40 = 0, p = 1;while (t--) {cin >> n >> str;res = 0, num4 = 0, num40 = 0, p = 1;for (LL i = 0; i < n; ++i) {if (str[i] == '4') {num4 = (num4 + p) % Mo;res = (res + num40) % Mo;} else if (str[i] == '0') {num40 = (num40 + num4) % Mo;} else if (str[i] == '*') {res = (res * 2 + num40) % Mo;num40 = (num40 * 2 + num4);num4 = (num4 * 2 + p) % Mo;p = (p * 2) % Mo;}}cout << res << '\n';}return 0;
}

洛谷 P2392 kkksc03考前临时抱佛脚

P2392 kkksc03考前临时抱佛脚 - 洛谷

若左脑(或右脑)已做完,右脑(或左脑)未做完,左脑可继续做题。

开始想过状压dp,dp[i][j] = 第i科做题状态为j(二进制,题已做对应位为1),如上条件存在,导致不能单纯枚举最后做的两道题,换思路。

贪心,局部最优:左脑和右脑算题时间差距最小,全局最优:最大值最小,多次计算可合并为一次计算。求加上若干做题时间后,<=sum(sum为当前科做题的总时间) / 2的最大值,sum减去该值得到结果。

用dp解:

  • 状态:dp[i][j] = 第i科里 ≤j时间的最大时间
  • 状态转移方程:dp[i][j] = max(dp[i][j], dp[i][j - vct[i]] + vct[i])(vct[i]是当前题的时间,vct[i] ≤ j)
  • 边界:dp[i][j] = 0
  • 结果: \sumdp[i][bagw]
#include <iostream>
#include <cmath>
using namespace std;typedef long long LL;const LL n = 4;
const LL Maxs = 20 + 5;
const LL Maxbw = 20 * 60 / 2 + 5;LL nums[n + 2], dp[Maxbw], vct[Maxs];void init(LL mVal) {for (LL i = 0; i <= mVal; ++i)  dp[i] = 0;return;
}int main() {ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);cin >> nums[0] >> nums[1] >> nums[2] >> nums[3];LL sum = 0, bagw = 0, res = 0;for (LL i = 0; i < n; ++i) {sum = 0;for (LL j = 0; j < nums[i]; ++j) {cin >> vct[j];sum += vct[j];}bagw = sum / 2;init(bagw);for (LL j = 0; j < nums[i]; ++j) {for (LL k = bagw; k >= vct[j]; --k)dp[k] = max(dp[k], dp[k - vct[j]] + vct[j]);}res += sum - dp[bagw];}cout << res;return 0;
}

总结

较为复杂的排列组合问题,分步求解,每一步将原问题拆解成子问题,根据子问题间的关系选择用加法原理还是乘法原理。

排列组合的关键是拆解子问题。

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

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

相关文章

SQL调优方案对比与最佳实践

问题背景介绍 在大型互联网或企业级应用中&#xff0c;数据库往往成为系统性能的瓶颈。随着数据量和并发量的增长&#xff0c;单一的 SQL 查询可能出现响应迟缓、锁等待、全表扫描等性能问题。为保证系统的稳定性和用户体验&#xff0c;需要对 SQL 查询做深入的调优。常见的调…

Terraform Helm:微服务基础设施即代码

&#x1f680; Terraform & Helm&#xff1a;微服务基础设施即代码 &#x1f4da; 目录 &#x1f680; Terraform & Helm&#xff1a;微服务基础设施即代码1. 引言 &#x1f680;2. 环境与依赖 &#x1f9f0;3. 架构示意 &#x1f3d7;️4. Terraform 定义云资源 &…

清理 Docker 缓存占用

Docker 缓存主要包括未使用的镜像、容器、卷和网络等资源。清理缓存可以提高磁盘空间&#xff0c;线上升级次数比较多的话&#xff0c;服务器中Docker缓存会非常严重&#xff0c;做下清理瘦身会有意想不到的效果 清理未使用的镜像 运行以下命令删除未被任何容器引用的镜像&…

深入解析NumPy的核心函数np.array()

深入解析NumPy的核心函数np.array NumPy与np.array()简介NumPy的重要性np.array()的作用 np.array()函数的详细参数object参数dtype参数copy参数order参数subok参数ndmin参数like参数 np.array()函数的使用示例创建基本的一维和二维数组创建具有特定数据类型的数组创建多维数组…

定时器的设计

定时器 定时器原理如何理解定时器定时器数据结构选取定时器触发方式 定时器的实现 定时器原理 如何理解定时器 定时器在日常通常被描述为组织大量延时任务的模块&#xff0c;其实从字面意思去理解的话&#xff0c;他就是去处理延时任务的&#xff0c;那么什么是延时任务呢&am…

大模型-分布式论文一瞥

1分离式架构 1.1 DistServe DistServe: Disaggregating Prefill and Decoding for Goodput-optimized Large Language Model Serving DistServe: Disaggregating Prefill and Decoding for Goodput-optimized Large Language Model Serving 讲的是一个将prefill和decoding分…

02.SpringBoot常用Utils工具类详解

文章目录 1. BeanUtils详解1.1 什么是BeanUtils&#xff1f;1.2 主要的BeanUtils实现1.2.1 Spring BeanUtils1.2.2 Apache Commons BeanUtils1.2.3 其他实现 1.3 Spring BeanUtils详细使用1.3.1 基本用法1.3.2 指定忽略属性1.3.3 批量拷贝&#xff08;列表转换&#xff09; 1.4…

Golang快速开发框架——项目立项与系统配置读取组件viper(一)

Golang快速开发框架——项目立项与系统配置读取组件viper&#xff08;一&#xff09; 背景 知识分享之Golang篇是我在日常使用Golang时学习到的各种各样的知识的记录&#xff0c;将其整理出来以文章的形式分享给大家&#xff0c;来进行共同学习。欢迎大家进行持续关注。 知识分…

打造可观测的 iOS CICD 流程:调试、追踪与质量保障全记录

随着iOS项目复杂度增加&#xff0c;团队越来越依赖自动化构建、自动化测试等CI/CD流程来保证产品质量。但CI/CD环境下&#xff0c;很多线下调试手段无法直接使用&#xff0c;比如&#xff1a; 无法手动连真机跑Instruments测试包只在分发后才能拿到崩溃模拟器上表现和真机不一…

C++11中 <cinttypes>的入门与精通

文章目录 一、<cinttypes> 是什么1. 固定宽度的整数类型2. 整数操作函数3. 格式化输入输出宏 二、深入理解 <cinttypes>1. 固定宽度整数类型的使用2. 整数操作函数的使用3. 格式化输入输出宏的使用 三、实践和技巧1. 使用固定宽度整数类型的最佳实践2. 使用整数操作…

Pytorhc Lightning进阶:一篇实例玩转Pytorhc Lightning 让训练更高效

Pytorhc Lightning进阶&#xff1a;一篇实例玩转Pytorhc Lightning 让训练更高效 Pytorhc Lightning 主要包含以下几大类&#xff0c;主要围绕以下讲解&#xff1a; 模型&#xff0c;PyTorch Lightning 的核心是继承 pl.LightningModule数据&#xff0c;数据模块继承pl.Light…

大模型算法面试笔记——注意力Transformer流程/面试题篇

学习资料来源于字母站大学 1 Transformer架构 基于编码器-解码器的架构来处理序列对。跟使用注意力的seq2seq不同&#xff0c;Transformer是基于纯注意力。 2 注意力 2.1 自注意力机制 使用注意力&#xff1a;需要根据整个序列进行预测&#xff0c;对于同一input&#xf…

Rust 定义与实例化结构体

文章目录 Rust 定义与实例化结构体5.1 结构体的定义与意义5.2 结构体实例化5.2.1 基本实例化5.2.2 可变性规则5.2.3 字段初始化简写5.2.4 结构体更新语法 5.3 特殊结构体类型5.3.1 元组结构体&#xff08;Tuple Struct&#xff09;5.3.2 类单元结构体&#xff08;Unit-Like Str…

ELK日志分析系统(filebeat+logstash+elasticsearch+kibana)

一、ELK 平台介绍 1、ELK 概述 日志主要包括系统日志、应用程序日志和安全日志。系统运维和开发人员可以通过日志了解服务器软硬件信息、检查配置过程中的错误及错误发生的原因。经常分析日志可以了解服务器的负荷&#xff0c;性能安全性&#xff0c;从而及时采取措施纠正错误。…

JS基础4—jQuery

jQuery常用内容 jQuery 介绍jQuery 获取方式基本选择器 (最常用)层级选择器 (基于元素间关系)过滤选择器 (基于特定条件) jQuery事件绑定jQuery 方法调用jQuery遍历jQuery 获取与设置jQuery 添加与删除jQuery CSS 类jQuery - AJAX 总结 jQuery 介绍 jQuery 是一个轻量级、快速…

时钟周期是什么?

时钟周期&#xff08;Clock Cycle&#xff09;是什么&#xff1f; 时钟周期&#xff08;Clock Cycle&#xff09;是计算机系统中一个最基础的时间单位&#xff0c;也称为时钟节拍或时钟周期时间&#xff08;Clock Period&#xff09;。它由系统时钟发生器产生的一个周期性脉冲…

如何用SEO优化长尾关键词?

内容概要 在SEO优化领域&#xff0c;长尾关键词扮演着至关重要的角色&#xff0c;它们能有效提升网站在搜索引擎中的可见度和流量转化率。本文将全面解析如何通过系统方法优化长尾关键词&#xff0c;涵盖从基础理论到实战应用的完整流程。核心内容包括利用专业工具进行关键词挖…

电子面单系统开发全解析

一、如果要做电子面单系统&#xff0c;怎么做&#xff1f; 开发电子面单系统是一项复杂且涉及多方面考量的工程&#xff0c;涵盖需求分析、系统架构设计、技术选型、接口对接、安全性保障、第三方服务选择以及部署与维护等关键环节。 电子面单系统开发步骤 需求分析&#xf…

UE5 - 制作《塞尔达传说》中林克的技能 - 18 - 磁力抓取器

让我们继续《塞尔达传说》中林克技能的制作!!! UE版本:5.6.0 VS版本:2022 本章节的核心目标:磁力抓取器 先让我们看一下完成后的效果: 18_磁力抓取器 大纲如下: 引言功能架构与核心逻辑物理材质与场景配置代码实现:从识别到操控操作说明1.引言 在《塞尔达传说》中,林…

基于ApachePOI实现百度POI分类快速导入PostgreSQL数据库实战

目录 前言 一、百度POI分类简介 1、数据表格 2、分类结构 二、从Excel导入到PG数据库 1、Excel解析流程 2、数据入库 3、入库成果及检索 三、总结 前言 在上一篇博文中&#xff0c;我们对高德POI分类进行了深入剖析 并对Excel 中 POI 分类数据的存储结构特点进行了详细介…