CF140E New Year Garland 题目分析

news/2025/3/11 19:19:54/文章来源:https://www.cnblogs.com/high-sky/p/18765821

CF140E New Year Garland 题目分析

挺不错的动态规划题目。

思路

一看到题目便可以知道每一层和层与层之间是要分开来算的(这种类似的动态规划还有很多)。

我们先看看层与层之间的。

层与层

题目要求:相邻的两层的小球颜色集合不相同

那么区分相邻两层小球颜色集合不同可以通过数量不同来区分,然后再进行讨论即可。

根据上述,显然地,设 \(f_{i,j}\) 表示已经完成前 \(i\) 层,到了第 \(i\) 层小球颜色集合的数量为 \(j\) 的总方案。

我们先抛开重不重复不谈,那么它的总方案肯定是从前面的那一层转移过来,即 \(f_{i-1,k}\),其中 \(k\in [1,l_{i-1}]\)

那么是不是就是

\[f_{i,j}=\sum_{k=1}^{l_{i-1}}f_{i-1,k} \]

呢?显然不是,这里的 \(j\) 是数量,并不是选了什么,因此还要有 \(C_m^j\) 来确定选 \(j\) 种颜色球的方案(这是对于当前 \(i\) 的)。

每一层

我们还需要当前这一层的贡献,而每一层的贡献求法类似,根据我们的总状态可以设 \(g_{i,j}\) 表示长度为 \(i\) 的位置给你放 \(j\) 种颜色(此处颜色确定,并且按从大到小的顺序排列)的球的放的方案是多少。

转移也是显然的:

\[g_{i,j}=g_{i-1,j-1}+g_{i-1,j}\times (j-1) \]

后面之所以要乘上 \((j-1)\) 是因为有 \(j\) 种颜色,并且不能与上一个相等,故为 \((j-1)\) 个。

合起来!

我们可以预先求出 \(g_{i,j}\),因此这个处理的复杂度为 \(\mathcal{O}((\max l_i)^2)\)

根据上述,我们不难把 \(f_{i,j}\)(不考虑层与层之间的要求)的求法合并为:

\[f_{i,j}=C_{m}^j\times g_{i,j}\times j! \times \sum_{k=1}^{l_{i-1}}f_{i-1,k} \]

实际上我们的每一层方案不一定是要从小到大排列的,因此我们乘上 \(j!\) 来保证每一种可能(这个可以理解为将这 \(j\) 个不同颜色原本按照一个一个编号排着,想通颜色的是同一个标号,然后你决定要将每个编号的每种可能都取到,这样就要乘上 \(j!\)),还不理解可以参考下述:

按照原本的转移我得到的所有可能情况是 \(\{a_i\}\)

比如说,我有 \(j\) 种颜色,将它们依次标号为:\(\{1,2,3,\dots,j\}\)

实际上我可以是:\(\{2,1,j,\dots,4\}\),或者是 \(\{4,1,j-1,\dots,j\}\) 等等都有可能。

但是这所有的情况总和便是 \(j!\)。触类旁通,枚举所有可能全排列(长度为 \(n\))的时间复杂度就是 \(\mathcal{O}(n!)\)

如果你还是不能理解就可以用数学的思想考虑:

总共有 \(j\) 个位置,我填在第 \(1\) 位的方案为 \(j\),第 \(2\) 位的为 \(j-1\)

易有:第 \(i\) 位的方案为 \(j-i\)

最后填完 \(j\) 个位置的方案为 \(j!\)

由于模数 \(p\) 不一定是质数,这就导致我们的 \(C_{m}^j\) 不能用逆元求解,但是我们发现:

\[P_{m}^j=C_{m}^j\times j! \]

于是合并一下:

\[f_{i,j}=P_m^j\times g_{i,j}\times \sum_{k=1}^{l_{i-1}}f_{i-1,k} \]

真是棒极了!现在我们考虑与上一层不同的情况,我们发现两层颜色集合相等的两种情况的充分条件是 \(k=j\)

然后我们又发现,两者颜色集合完全相等在 \(C_{m}^j\) 种只有一种情况。

故我们可以得到:

\[f_{i,j}=P_m^j\times g_{i,j}\times \sum_{k=1}^{l_{i-1}}f_{i-1,k}-f_{i-1,j}\times g_{i,j}\times j! \]

这个乘上 \(j!\) 与上述同理。

一些提示(思考后再看)

我给出两个提示:一是怎么求 \(P_{m}^j\),二是怎么优化。

有人说:

\[P_{m}^j=\frac{m!}{(m-j)!} \]

这不还是要逆元吗?

但我说:

\[P_m^j=\prod_{i=m-j+1}^mi \]

而显然:

\[P_m^0=m \]

然后从 \(i-1\) 做到 \(i\) 不就行了,每次只多乘上一个数。

如何优化?

其实很简单。

我们发现:\(\sum_{k=1}^{l_{i-1}}f_{i-1,k}\) 其实跟 \(j\) 没有任何关系,直接在枚举 \(i\) 的时候加一下不就完了。

代码

\(L=\max l_i\),总时间复杂度为 \(\mathcal{O}(L^2+\sum l_i)\)

代码如下:

#include <iostream>
#include <cstdio>
#include <stdlib.h>
#include <algorithm>
#include <cstring>
#include <vector>
#define int long long
#define N 1000006
#define M 5005
using namespace std;
int n,m,mod,l[N],g[M][M],mxm,p[N],f[2][M],jc[M];
signed main(){cin >> n >> m >> mod;for (int i = 1;i <= n;i ++) cin >> l[i],mxm = max(mxm,l[i]);jc[0] = 1;for (int i = 1;i <= mxm;i ++) jc[i] = jc[i - 1] * i % mod;g[1][1] = 1;for (int i = 2;i <= mxm;i ++)for (int j = 1;j <= min(i,m);j ++)g[i][j] = (g[i - 1][j - 1] + g[i - 1][j] * (j - 1) % mod) % mod;
//	cout << g[2][2] << ' ' << p[2] << ' ' << p[1] << endl;p[0] = 1;for (int i = 1;i <= mxm;i ++)p[i] = p[i - 1] * (m - i + 1) % mod;for (int j = 1;j <= min(l[1],m);j ++)f[1][j] = g[l[1]][j] * p[j] % mod;for (int i = 2;i <= n;i ++) {int sum = 0;for (int k = 1;k <= min(m,l[i - 1]);k ++)sum = (sum + f[i - 1 & 1][k]) % mod;
//		cout << sum << endl;for (int j = 1;j <= min(m,l[i]);j ++) {f[i & 1][j] = sum * g[l[i]][j] % mod * p[j] % mod;if (j <= l[i - 1]) f[i & 1][j] = (f[i & 1][j] - f[i - 1 & 1][j] * g[l[i]][j] % mod * jc[j] % mod + 5 * mod) % mod;
//			cout << f[i & 1][j] << endl;}}int ans = 0;for (int j = 1;j <= l[n];j ++)ans = (ans + f[n & 1][j]) % mod;cout << ans;return 0;
}

提示一个很容易错的点:直接算 \(f_1\) 的时候记得取模,不然大数据过不了

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

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

相关文章

设备与onenet服务器之间的mqtt通讯

设备与onenet服务器之间的通讯 1. 登录onenet平台2.创建产品3.设备管理 1)创建两个进行测试功能4.MQTTfx测试password计算工具官网下载:OneNET - 中国移动物联网开放平台1)订阅属性上报结果通知消息 Subscribe的topic: $sys/改成自己的产品ID/改成自己的设备名称/thing/pro…

设计一个优秀 API 的秘诀

本指南深入探讨了顶级 API 设计,强调了它不仅仅是代码的集合。一个设计良好的 API 就像五星级礼宾服务,能够顺畅地引导用户达到他们的预期目标。拿起一杯咖啡,让我们一起探索创建一个功能强大、用户友好的 API 的秘诀吧! 理解 API 基础第一步:拥抱 REST - API 设计的基础 …

T428497 请不要抢走爱丽丝的工作! 题解

T428497 请不要抢走爱丽丝的工作! 题解题目传送门 本题要求扫地机器人半径 \(r\) 的最大值,既然要求最大值,容易想到二分答案。 那问题就转换为给定半径 \(R\) , 判断 \(R\) 满不满足条件,也就是能不能找到一条绕过所有障碍的路径。让我们逆转一下思维,考虑哪些区域是机器…

个人作业:软件案例分析

个人作业:软件案例分析项目 内容这个作业属于哪个课程 首页 - 2025年春季软件工程(罗杰、任健) - 北京航空航天大学 - 班级博客 - 博客园这个作业的要求在哪里 [I.2] 个人作业:软件案例分析我在这个课程的目标是 学习软件开发流程,完成一次完整的软件开发经历,提高开发和…

API 调试与管理工具选型思考:Apifox vs Apipost,企业究竟该如何选择

在企业级 API 调试与管理场景中,选择一款高效的工具至关重要。市面上的调试工具琳琅满目,而 Apifox 和 Apipost 是近几年两款备受开发者关注的 API 工具。二者都宣称为团队协作和接口调试赋能,但对企业来说,究竟谁才是更适合的选择呢?本文将从功能对比、用户体验、企业适配…

pos_cli 命令是如何运行起来的

追踪pos_cli --dump --dir /root/ckpt --pid [your program pid] 是如何运行的 pos_cli是通过mason,由sources包括的这些文件构建而来 #pos/cli/meson.buildproject_name = phoenix_os_cli project_name_abbreviation = pos_cli scan_src_path = meson.current_source_dir() +…

Tavus 发布对话轮次控制模型:能理解对话节奏和意图;百度推出 AI 情感陪伴应用月匣,整合 MiniMax 等模型丨日报

开发者朋友们大家好:这里是 「RTE 开发者日报」 ,每天和大家一起看新闻、聊八卦。我们的社区编辑团队会整理分享 RTE(Real-Time Engagement) 领域内「有话题的 技术 」、「有亮点的 产品 」、「有思考的 文章 」、「有态度的 观点 」、「有看点的 活动 」,但内容仅代表编辑…

clickhouse 25.2.1 集群部署

依赖条件 sysctl.conf echo "kernel.threads-max = 262144" >> /etc/sysctl.conf && sysctl -p Huge Pages(按需修改) 编辑 /etc/default/grub,在 GRUB_CMDLINE_LINUX 参数中添加: GRUB_CMDLINE_LINUX="... transparent_hugepage=never"…

可视化图解算法:链表指定区间反转

对于链表的相关操作,我们总结了一套【可视化+图解】方法,依据此方法来解决链表相关问题,链表操作变得易于理解,写出来的代码可读性高也不容易出错。1. 题目 描述 给你单链表的头指针 head 和两个整数 left 和 right ,其中 left <= right 。请你反转从位置 left 到位置 …

ov5640原理讲解

Camera开发-OV5640(MIPI)-CSDN博客

[I.2] 个人作业:软件案例分析

[I.2] 个人作业:软件案例分析项目 内容这个作业属于哪个工程 https://edu.cnblogs.com/campus/buaa/BUAA_SE_2025_LR这个作业的要求在哪里 https://edu.cnblogs.com/campus/buaa/BUAA_SE_2025_LR/homework/13367我在这个课程的目标是 学习团队软件开发方式, 丰富开发经验这个作…

应对SQLyog trial到期方式:删脚本!

(1)进入注册表中的HKEY_CURRENT_USER\SOFTWARE路径 (2)找到{d58cb4b1-47f3-45cb-a209-f298d0c3f756}文件夹 删除掉!! (3)到期了删一回