DP notes
P4934 礼物
不知道什么类型 dp。
只枚举给出的数显然不行,考虑从值域入手。枚举值域内的所有数,枚举每一个数二进制下的子集,设 \(f_i\) 表示 \(i\) 这个数应该放在第几组:
\(vis\) 表示是否是题给的数。
这样显然还是超时,子集枚举应该是 \(\operatorname{O}(3^k)\)。注意到只需要考虑从 \(i\) 中删去一个 \(1\) 的 \(j\) 即可,其余在以前都计算过了:
\(\operatorname{O}(2^k\times k+n)\)。
P5664 [CSP-S2019] Emiya 家今天的饭
dp 带了容斥。
数学加 dp,这下更不会了,完蛋。
简单来说是给定一个矩阵,和每一个元素可以选的次数。同一行的元素只能选一次,同一列所选不能超过总的一半,不能不选,求总方案数。
每一行一个元素是非常友好的限制,而注意到不符合限制的列最多只有一列,我们可以默认每一行选一个,算总方案数和不符合列限制的方案数,相减即可。
总方案数十分好计算,\(s_i\) 为第 \(i\) 行的和,每一列算上不选一共有 \(s_i+1\) 种选择,去掉什么也不选的,则为:
之后直接枚举每一列作为不符合限制那一列,记为 \(col\)。
设 \(f_{i,j,k}\) 表示前 \(i\) 行在当前列选了 \(j\) 个,在其他列选了 \(k\) 个。则有:
第一项是什么也不选,第二项是这一行选本列的,第三项是选其他列的,很好理解吧!
然后不符合条件的方案数:
但是这样是 \(\operatorname{O}(mn^3)\) 的,无法通过。经过查看题解深思熟虑以后,我们发现我们只关心 \(j>k\) 的情况,也就是 \(j-k>0\) ,不需要知道具体大小。那重新设计状态,让第二维表示 \(j-k\) 的大小,即 \(f_{i,j}\) 表示前 \(i\) 行,当前行选的比其他行多了 \(j\) 个,状态转移方程为:
这样可能会有负数下标,把第二维都加上 \(n\) 即可。
P1453 城市环路
无向基环树最大权独立集
我真的讨厌基环树 dp,*发怒*
本质上是一个没有上司的舞会,然后放到了基环树上,考虑随便断开一条环上的边,然后由两种做法:
- 对于端点 \(u\) 和 \(v\),分别作为新树的根进行 dp,然后只统计 \(f[rt][0]\),这样可以覆盖所有情况。
- 钦定一个点为根,然后进行两次 dp,第一次强制选根,那另外那个叶子就强制不选,具体操作是 \(f[v][1]\gets \operatorname{INF}\);第二次强制不选根,就不需要额外操作了。
dp 的部分很简单,就不说了。
P2607 骑士
这个题就不单独说了,是一个有向基环树森林,只能采取上题的方法 \(2\)。
AcWing 359 创世纪
首先注意到:\(i\) 限制 \(A[i]\),然后每种元素只限制另外一种元素,显然是基环树。我们从 \(A[i]\) 向 \(i\) 连边,也就是一条边 \(u\to v\) 表示 \(u\) 被 \(v\) 限制,是外向树森林。问题转化成一个外向树森林,一个节点如果要选,那么它的子节点至少有一个未选择;否则不选。要求选择的点最多。
考虑树上的做法。设 \(f[u][0/1]\) 表示 \(u\) 选或不选子树中选择的最多点数。
首先如果 \(u\) 不选,子节点随便。
如果 \(u\) 选,子节点要有一个不选,用一个小容斥,把贡献最小的去掉就好了:
CF1955H. The Most Reckless Defense
给敌人加血可以看成是减少防御塔的攻击力,那么一个塔对敌人能造成的最大伤害即为 \(500\pi r^2-3^r\),注意到 \(r=12\) 时已经小于 \(0\) 了,所以半径不会很大,又因为每个 \(r\) 只能选一次,所以有效的塔很少,考虑状压 \(dp\)。
具体地,我们设 \(f_{i,S}\) 表示前 \(i\) 个塔中,被选到的塔的半径集合为 \(S\),所造成的伤害(攻击力)为多少。显然最后答案就等于最大的伤害。有转移方程:
含义很简单,就是当前选或不选。\(calc(i,r)\) 表示第 \(i\) 座塔半径为 \(r\) 时能攻击到几次敌人。预处理 \(calc\) 的复杂度为 \(\mathcal{O}(k\cdot R^3)\),\(dp\) 的复杂度为 \(\mathcal{O}(k\cdot R\cdot 2^R)\),总复杂度 \(\mathcal{O}(k\cdot R\cdot (R^2+2^R))\)。
其实也可以最后一起减去 \(\sum 3^r\) 的,两种都对。一开始我不理解为啥两种写法是等价的,想了想,大概是因为每次取 \(\max\) 的两项只差一个 \(r\),所以要么都减了,要么都没减,不影响相对大小,也就不影响结果。
其实这题还能费用流。每个塔作为左部点,\(12\) 个半径作为右部点,边权或者说费用就是 \(p_i\times calc(i,r)-3^r\),跑一遍二分图带权最大匹配,也就是最大费用最大流即可。不过我没写,口胡的。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现