NOIP2023模拟赛 种树
1|0动态规划思路
1|1可行性
抛开取模问题和空间限制,该题存在最优子结构性和无后效性,而这两个问题都可以另外处理。
1|2状态定义
1|3状态转移
先忽略取模问题
推导状态转移方程
不选择对当前第 i 个树木施肥。
显而易见,
选择对当前第 i 个树木施肥。
这里的
- 显然必须小于总化肥量。
是 的正因数。- 从题干中(要求
必须为当前化肥量的正因数)推出,所有状态的当前化肥量显然只能是总化肥量 的正因数。
- 从题干中(要求
由此可以推导出,
预处理出来
代码实现
首先初始化初状态
即剩下
状态转移实现
到此,我们算是在无视取模和空间限制的情况下完成了状态转移。
1|4快速求因子数
问题来由
用动态规划实现复杂度接近于
处理方法
依靠两个结论
- 一个正整数一定能分解为若干质数
次方的乘积。 - 一个数的因子数等于该数分解为若干质数
次方的乘积后每个质数的次方数加一的乘积。
举个例子
那么因子数则是
代码实现
1|5处理取模问题
问题来由
最优性问题每次都要判断大小,而取模判断大小很可能出现各种问题。
比如假设对
而动态规划时每次判断最优解就会被这个问题影响正确性。
处理方法
仅针对本题,取模的对象是通过乘法进行状态转移的,那么问题就转移到了如何正确的在状态转移时判断两个状态的大小。
除了习惯性的直接比较两个状态的大小外,可以利用乘法的性质,即两数相乘正比于两数对数相加。
如此,我们维护一个数组 DP
,DP
和 F
数组同步操作,只是所有的相乘改为取对数相加。显然对数的数量级不会越界,不需要取模,也保证了正确性。
代码实现非常容易,即所有的相乘操作都换成对数相加。
初始化加入:
不选择对当前第
选择对当前第
1|6优化空间
问题来由
本题的long
和 double
。
这导致了 MLE。
处理方法
MAP 思路
从状态转移方程的推导不难看出,因为剩余化肥数只能从
有什么办法能解决呢,蒟蒻我觉得最好实现的就是用 map
来维护两个动态规划数组。
map
本质上也是个容器,但是它只有用到了才会开辟空间,即放入这个元素到 map
容器内。
这真正做到了没用到的就不开辟空间。
实现
即维护一个 map<pair<int, int>, int or double>
。
pair
用来替代动规数组的两维,而 int
或 double
用来存动规数组的值。
代码非常简单,首先开辟两个动规数组。
之后把原来代码所有的下标改为 pair
即可。
滚动数组思路
经 @User439000 提醒,我发现这题也完全可以用滚动数组优化。
由于对
实现
首先开两个一维数组来代替 F
和 dp
。
由于滚动数组的更新仍需要从上一个状态开始,而本动态规划算法的状态更新是每轮从剩余肥料大到小更新的。因此第二层枚举当前肥料剩余量的循环应从小到大,这样可以保证每次更新时使用的是上一次更新的状态。
1|7代码实现
map 优化内存实现
滚动数组优化内存实现
1|8结语
昨天模拟赛想了三个小时没想出来处理取模问题心态爆炸,觉得自己白想了,自己方法不可行,气的晚上睡不着。
到今天终于把这个做法完善通过,很喜悦。
很多时候路都是走出来的。
十一月十二号二十点整于旗山实验室。
__EOF__

本文链接:https://www.cnblogs.com/kdlyh/p/17826185.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角【推荐】一下。您的鼓励是博主的最大动力!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 记一次.NET内存居高不下排查解决与启示