DP套DP
有些时候,对于某一个数列(或者串等其他东西),我们可以使用DP判断其是否合法。
于是有毒瘤人们就会想到一种题目,对于这种需要用DP来判断是否合法的东西,能不能对其进行计数呢?
对于有些是可以的。
我们考虑一下:因为DP本来就是一个有限状态自动机,也就意味着转移和状态数都是固定的,如果我们把状态通过编号或者状压压到一维,我们就可以处理了。而方案数统计本来就是一个DP,所以这种神奇的方法就叫做DP套DP。
DP套DP大概就这么多,还是要上题:
[TJOI2018]游园会
给定长度 \(N\) 和由N
,O
,I
组成的串 \(S\)。问有多少个长为 \(N\),且由N
,O
,I
组成的串与 \(S\) 的最长公共子序列的长度为 \(m\) ,且串中不含NOI
的串的个数。
输出对于 \(m=0,1\dots|S|\) 的答案。
我们考虑如何检验一个串 \(T\) 的与 \(S\) 的最长公共子序列长度和是否含有串 NOI
。
对于前者,我们的朴素想法是维护 \(f_{i,j}\) 表示串 \(T\) 的前 \(i\) 位和串 \(S\) 的前 \(j\) 位的最长公共子序列。
对于后者,我们会选择跑KMP,但由于匹配串NOI
长为3且字母互不相同,其实就是N
,O
,I
这三个字符之间的转移,有些可行有些不可行。
后者很容易被压在 \(0,1,2\) 中,我们就需要考虑前者如何处理。
我们再来看一下前者的转移,\(f_{i,j}=\begin{cases}\max(f_{i-1,j},f_{i,j-1})&T_i\neq S_j\\\max(f_{i-1,j},f_{i,j-1},f_{i-1,j-i}+1)&T_i=S_j\end{cases}\) 。
通过数学归纳或者感性理解,我们会发现:\(f_{i,j}-f_{i,j-1}\leq 1\) ,这也就意味着,我们其实可以用一个长度为 \(|S|\) 的二进制数来表示一行的转移。
我们只需要处理出来 \(2^{|S|}\) 种情况分别对于 \(T\) 下一位为N
,O
,I
的转移即可。
我们外层的DP就是 \(F_{i,S,j}\) 表示处理到了第 \(i\) 为,最长公共子序列的匹配为 \(S\) ,与NOI
匹配到了第 \(j\) 位时的方案数。
总体复杂度 \(O(n2^{|S|})\)
CF979E Kuro and Topological Parity
还没有写捏
[ZJOI2019]麻将
upd on 2024.02.28
没想到会有时间补这个,很厉害。
对于我们手上拿到的牌,记 \(a_i\) 为我们拿到的大小为 \(i\) 的牌的数量,我们考虑如何判断一副牌是否满足条件。也就是我们想要建立一个自动机,把 \(\{a_n\}\) 逐位扔进去就可以得到结果。
记 \(dp_{i,j,k,0/1}\) 表示,处理到了大小 \(\le i\) 的所有牌,预留了 \(j\) 个 \(i-1\) 和 \(i\) 作为 \(i-1,i,i+1\) 的顺子,\(k\) 个 \(i\) 作为 \(i,i+1,i+2\) 的顺子,有没有对子的情况下,最多有多少个面子。如果任何时刻某一个状态的 \(dp_{i,j,k,0/1}\ge 4\) 了,就说明这副牌胡了。显然有 \(j,k<3\),否则可以将其拆成刻子。
考虑转移,我们加入了 \(a_{i+1}\) 个 \(i+1\),考虑 \(dp_{i+1,k,l,0/1}\gets dp_{i,j,k,0/1}\),显然有 \(a_{i+1}\ge j+k+l\),所以可以组成 \(\left\lfloor\dfrac{a_{i+1}-j-k-l}{3}\right\rfloor\) 个刻子,如果我们要留下一组对子就用 \(a_{i+1}-2\) 转移即可。
考虑到胡牌还有可能是七小对,所以我们在单独维护一个有多少个 \(a_i\ge 2\)。
这样我们可以存储 \(dp_{0/1,i,j}\) 以及一个 \(pair_cnt\) 来维护一个状态,我们使用 bfs 对其建自动机,发现只有 \(M=2092\) 种状态。
然后用 \(dp_{i,j,S}\) 表示处理了大小 \(\le i\),一共有 \(j\) 张牌,状态为 \(S\) 的方案数。
那么最终会答案就等于 \(1+\sum\limits_{t=1}^{4n-13}F(t)\),其中 \(F(t)\) 为摸 \(t\) 张牌没有胡的方案。
时间复杂度是 \(O(Mn^2)\) 的。
[NOI2022]移除石子
神秘思维题,详见Alex_Wei老师,因为我也是在他的博客里学的。
我们一层一层的来思考:
第一步、考虑如何检验某种石子情况是可行的的。
不难发现选择长度 \(\geqslant 3\) 一个区间,相当于选择若干次长度 \(=3,4,5\) 的区间;同时存在一种方案不会选择同一个区间 \(2\) 次。这两件事情告诉我们,我们从每一个位置开始的区间数会 \(\leqslant 3\) 个。
所以我们就可以考虑维护 \(f_{i,j,k,l}\) 表示,\(i\) 之前的位都已经处理了,现在有 \(j\) 个可以选择延伸到第 \(i\) 位,有 \(k\) 个必须延伸到第 \(i\) 位,有 \(l\) 个必须延伸到第 \(i+1\) 位。
我们假设可以延伸的我们选择了 \(p\in[0,j]\) 个,在满足 \(a_i=p+k+l\) 或 \(a_i\geqslant p+k+l+2\) 的情况下,我们得到转移 \(f_{i,j,k,l}\rightarrow f_{i,p+k,l,st},st\in[0,3]\),最终检查 \(f_{n+1,*,0,0}\) 是否存在即可。
我们考虑两个优化:如果我们同时在第 \(i\) 位开启了一个 \(4\) 和 \(5\),我们可以把它变成 \(i+1\) 位的 \(3\) 和 \(4\),也就意味着我们可以不同时取 \(3,4,5\),所以 \(j,k,l\leqslant 2\);我们可以钦定有哪些会延伸到第 \(i\) 位,也就是枚举 \(p\in[k,j+k]\) ,这样我们维护的DP就变成了 \(f_{i,j,k}\) 其中 \(j\leqslant 4,k\leqslant 2\) 了。
据Wei老师做写,我们可以枚举验证第二位 \(j\) 也是可以降到 \(j\leqslant 2\) 的。
第二步、转化恰好 \(k\) 的这个条件。
在这种问题里,恰好一定是比至多难做的,所以考虑能不能转换一下。
当 \(k=0\) 时,等价于我们上面的转移。
当 \(k=1\) 时,如果有一次操作1,则必然可行;只要有一次长度大于 \(4\) 的操作2,则必然可行;只要 \(n>3\) 且有一次长度大于 \(3\) 的操作2,则必然可行。
对于上述情况的方面,我们会发现只有两种,第一种是 \(a_i=0,i=1,2\dots n\),第二种是 \(n=3\) 且 \(a_1=a_2=a_3=1\)。
当 \(k=2\) 时,对于 \(k=0\) 时可行的,\(k=2\) 一定可行,对于 \(k=1\) 可行的,我们发现不可能出现 \(k=1\) 时将有解变无解的情况,(因为你根本不可能在上面的两种情况中删掉石子还保证有解),我们可以重复一次 \(k=1\) 来达到 \(k=2\) 的效果。
同理,我们便得到,当 \(k>1\) 时,放恰好 \(k\) 合法的方案数,等价于放 \(\leqslant k\) 个石子合法的方案数。
第三步、考虑得到某种石子情况至少需要加入多少个石子。
我们模仿第一步,维护 \(g_{i,j,k}\) 表示 \(i\) 之前的位都已经处理了,有 \(j\) 要延伸到第 \(i\) 位,\(k\) 个延伸到第 \(i+1\) 位,至少需要加多少个石子。
假设 \(i\) 位有 \(a_i\) 个石子,记 \(v=a_i-p-j-k\) ,其中 \(p\in\{0,1,2\}\) 表示我们在第 \(i\) 位新开的区间数。
如果 \(v<0\) 我们显然至少需要 \(-v\) 个石子,如果 \(v=1\) ,由于不能进行操作1,我们需要 \(1\) 个石子,其他情况不需要石子,所以得到转移 \(g_{i,j,k}+ned\rightarrow g_{i,st,p},st\in[k,k+j]\)。
第四步、考虑外层DP 时 \(a_i\) 的影响。
由于 \(p+j+k\) 范围较小,同时根据对拍或达标,我们会发现,对于 \(a_i\geqslant 6\) 的情况时等价的。
所以有意义的转移只会有 \(a_i=0,1,2,3,4,5\) 和 \(a_i\geqslant 6\) 这 \(7\) 种。
我们DP套DP的雏形已经出来的,但由于 \(k\leqslant 100\) ,也就意味这每一个 \(g\) 的取值是 \([0,101]\) ,似乎有 \(102^9\) 种状态。
第五步、保留有用的内层DP。
我们感性理解,发现 \(g\) 的值应该不会差的太远,所以有用的 \(g\) 的组合应该是有限的。
所以我们考虑暴力维护一边所有的转移,可以发现有效的转移数是 \(S=8765\) 种。
预处理出来所有转移,DP即可,最终复杂度 \(O(TnS)\) 。