【典】P6773 和区间有关的 dp 的一种简单状态+线段树(合并)维护dp
拿命运做标题其实是因为最广为人知吧,主要是总结这种 dp 设计方法以及线段树维护的巧妙之处。
已知一个序列,有 个区间修改(限制条件),求有多少方案数(最小最大值)。
这种区间的限制一般比较阴间,没有那么简单。
这里要介绍的一种方法就是列状态 表示 已经填好,接下来对 产生影响的区间的右端点的最大值(最小值)为 ,在区间的加持下,一般可以用线段树进行优化。
这种做法的好处是转移很简单,而且思维难度较低,线段树优化一般也比较显然,不需要对复杂的区间关系进行处理。
先来个简单题。
ARC085F *3094
有一个长度为 的序列 ,现在有一个初始全部是 的序列 ,有 种操作,每种操作可以把一个区间 全部变成 ,定义一个序列的价值为 ,求若干次操作后的最小价值。
。
纵观洛谷题解和 AT 题解,都可以发现做法要么把区间设进状态里,要么对区间关系进行分类讨论,或者进行复杂转化,总之,思维难度大,代码也不是很好写。
来一个无脑解法。
设 表示填完前 个了,那么考虑前面的区间会对后面造成的贡献是什么,自然就是覆盖为 的区间的右端点,因此 就表示前面选了的区间的右端点最大值。
有了这个状态,转移方程就十分自然。
后面的需要满足 是一个操作,这样可以直接前缀 维护。
意思就是如果选一个区间,那么就是右端点和 取一个 即可,一个区间在它的左端点选。
这样就可以得到一个 的 dp,code。
考虑怎么优化这个式子。
其实也比较简单,用一个线段树动态维护,把第一维扔掉,那么第一个式子就是前缀,后缀加,第二个式子就可以直接前缀查 ,单点修改。
代码不是最短的,但写起来非常无脑。
CF930E *2900
一个长度为 的 串,给出 个约束条件,其中 条描述区间 至少有一个 ,其中 条描述区间 至少有一个 。求合法的 串数量,答案对 取模。
。
标签:dp,线段树。
和上面一题差不多,也是直接用 dp 式子。
先设 表示 填完,左端点在 左边,没有被满足的 限制右端点最小是 , 限制是 的是 的方案数。
然后发现 要么填 要么填 ,所以必然有一个限制可以扔掉,所以状态变成 。
然后转移就很简单,直接讨论 填什么即可,可以看 暴力代码,时间复杂度 。
然后发现这个东西可以用线段树优化,分析一下转移方程可以发现是一个后缀加到一个点上以及区间清空,如果后面没有限制 就给个最大值,所以可以直接维护,时间复杂度 。
然后发现可以离散化,中间状态就是满足至少有一个 或者 去转移,也就是$ 2^s-1s$ 为区间长度,时间复杂度 。
给定一棵 个点的树和 条限制,你可以给树上的每一条边赋一个 或 的权值。对于所有限制 (保证 为 的祖先) 你需要保证 到 上至少有一条边的权值为 ,求赋值方案数。
考虑暴力 dp 咋做,本质上就是上面题的树上版本。
依然用前面的状态 表示在 子树中所有下端点限制中,没有满足的上端点的深度最大值是 , 子树中的填边方案,因为如果有多个不满足条件的上端点,显然取最下面哪一个,因为最下面的满足了上面的也一定满足,如果 ,则表示条件都满足。
考虑咋转移。
如果 的儿子是 ,那么如果 填 ,那么与状态没有啥关系,直接加和就好了。
否则考虑填 ,那么此时状态第二维就要取两者较大值。
最后可以得到转移方程:
令 表示限制中以 为下端点的,上端点深度最大值,那么初值就是 。
暴力代码可以看卡老师的,时间复杂度 。
考虑咋优化。
可以考虑线段树合并,每个节点开一棵线段树,分别表示状态,然后考虑状态咋合并。
第一个式子直接从左向右合并时维护和即可。
第二个就是一个 卷积,也是直接维护前缀和。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 【杂谈】分布式事务——高大上的无用知识?