自动机上 DP
概述
- 自动机上 DP 是在自动机上进行的一类 dp。除此之外,我目前没能提炼出什么共性。
建自动机式问题
-
典型代表如 \(\text{MarsOJ OI-Contest 7th T3 炉石 hearthstone}\)。
-
特点是题目给出了...怎么说呢,题目规定了一个局面自动机,然后要求在该自动机上计数/求期望之类的。
-
更具体的,我还得做做题...
MarsOJ OI-Contest 7th T3 炉石 hearthstone
-
题意:
-
双方打牌。
-
一开始,每方有一个奴隶主在场上。
- 奴隶主:随从。生命值为 \(3\)。受攻击时,如果本次攻击没有导致该奴隶主死亡,那么触发他的技能,召唤一个新的满血奴隶主。特别地,每方场上只能同时存在至多 \(7\) 个奴隶主。
-
然后攻击 \(n\) 次。
- 攻击:有 \(\dfrac{2}{3}\) 的概率打到我方随从(等概率选一个),\(1/3\) 的概率打到敌方随从(同上)。容易证明任意时刻双方都总是有随从。
-
求最后场上期望剩多少个奴隶主。
-
-
数据范围:\(n\leqslant 10^9,T\leqslant 5\),\(T\) 为数据组数。
-
乍一看就是个状压+矩阵快速幂优化/拉插优化,对吧?
-
容易想到 \(4^7\) 的 \(sta\) 记录一方场上的随从情况,但显然不能接受。
-
转化一下,\(7^3\) 的状态记录“有多少个 \(i\) 血的随从”。显然不用记录有多少个 \(0\) 血的,作差即可——其实我们也不关心。
-
但是打敌我概率不一样,很烦。于是我想到了 \(21^3\) 的状态,把每个我方的随从拆成两个。当然,还是炸飞。
-
观察到敌我互不影响,考虑分别 DP。其实相当于攻击我方 \(\dfrac{2n}{3}\) 次,敌方 \(\dfrac{n}{3}\) 次,\(\bmod\ 3\) 的余数可以暴力——很麻烦,但可以试试。
-
好想法,于是我们现在有了 \(7^3\) 的状态,复杂度为 \(T\times a^3\times\log n,a=7^3\),纸面复杂度 \(60\times 10^8\)。但显然还是过不了。怎么办?
-
-
首先这里有一个小 \(trick\),构建转移矩阵的时候把挨打概率构建进去。于是没有那个繁琐的暴力了。
-
然后我们终于走到核心:
-
\(7^3\) 的状态其实是比较冗余的。容易证明,三位上的数字的和 \(\leqslant 7\),故有很多无效状态。
-
考虑建出“奴隶主自动机”,局面即双方的奴隶主情况为点,攻击为边(可以认为边本身就是题意中的攻击,也可以认为是 dp 转移时带权转,当然权就是概率)。我会爆搜!以 \(001\) 为初始状态,暴搜出所有状态并编号,然后连边。
-
实际的结果是,状态数只有 \(119\)。作为对比,\(7^3=343\)。于是我们的纸面复杂度降至 \(2\times 10^8\),原题时限 \(2s\),但有理由认为预处理转移矩阵的整二次方幂代替快速幂之后,\(1s\) 也能随便过。实践中,最大点 \(492ms\)。
-
23.1.12 T1 实用和
- 版权原因,请移步查看。同校的可以找我要截图。
DP 套 DP
-
典型代表如 \(\text{P4590 [TJOI2018] 游园会}\) 和 \(\text{P8497 [NOI2022] 移除石子}\)。
-
特点是通常给出一个部分未定的元素集,选取该元素集的某个要素(不是集合中的元素),该要素在元素集确定时有简单 dp 做法可以判定或求出,然后要求对该要素的相关信息计数。注意虽然数位 DP 看起来挺符合这个定义的,但它显然不是 DP 套 DP。
-
状态设计通常为先把原 dp(记为 \(f\))的 DFA 拍出来,然后设计 \(F_{i,sta}\) 表示考虑完前 \(i\) 个,当前在 f 上的全信息为 \(sta\) 的方案数。
-
具体谈一下吧。我们这里要求 f 是在线行进的,故显然不能只记录 f 在 \(i\) 时的结果,而是要记录在 \(i\) 时的全信息,也可以说是把 \(f_i\) 作为一个向量压进了我们的状态里。
-
关于数字还有我的麻将假做法中的那种多路并行,我现在没想到太好的描述方法。当然,上面的这种其实也可以描述为一种多路并行,然后同时进行同 cate 的转移...
-
-
初始化通常为 \(F_{0,\text{f 的初始化}}=1\)。
-
状态转移通常为枚举下一位是什么,然后转移到对应的 \(sta\) 上。特别地,如果 \(f\) 也有 \(sta\),我可能会把 \(F\) 的写成 \(STA\) 来区分,强调 \(STA\) 的集合性时也会这么写。
-
复杂度通常和内部 dp 的状态数和内部 dp 的向量的有效状态数强相关,状态数少的话就很优秀,也因此常常极限压缩内部 dp 的状态并在外部剪除转移。
某内部赛 T4 拳击比赛
-
该比赛已解密,但我也不知道去哪里能找到,毕竟我校 OJ 需要权限。
-
题意:
-
\(2^n\) 个人打淘汰赛,这些人的实力 \(f_{1\sim 2^n}\) 恰为一个 \(1\sim 2^n\) 的排列。每轮相邻的两个人打,强者必胜。
-
现在实力为 \(1\) 的你买通了 \(m\) 名选手 \(key_{1\sim m}\),这些被买通的选手如果遇到你,就会打假赛输给你。
-
另外,这些人的前后顺序可以由你随意安排,因为你买通了比赛方。
-
求有多少种安排的方式,可以使得你不仅赢得比赛的冠军,而且被你打败的人的实力构成的数列的最长上升子序列长度 \(\geqslant k\)。
-
-
数据范围:\(1\leqslant k\leqslant n\leqslant 9,m\leqslant 16\)。
-
感觉很难,先试水分析下 \(k=1\) 的情况,则此时问的就是能赢的总方案数。
-
考虑先把自己放在 \(1\) 处,把整个淘汰树画出来。
-
发现一个显然的事情:被我打败的每个人依次是一个 \(siz=2^0,2^1,2^2,2^3,...,2^{n-1}\) 的子树的最终赢家,即那么大的子树中的“最强者”。
-
显然状压!考虑到每次要往对应的子树里选比最强者小的人当垫材,设计如下 dp:
-
状态设计:\(dp_{i,sta}\) 表示将 \(key\) 按 \(f\) 递增排序后,当前考虑完毕了第 \(i\) 个被买通的人,\(sta\) 对应的那些子树已经填过人了,的方案数。
-
初始化:\(dp_{0,0}=1\)。
-
状态转移:
-
\(dp_{i,sta}\to dp_{i+1,sta}\),转移系数为 \(1\)。即不让这个人负责一个子树。
-
\(dp_{i,sta}\to dp_{i+1,sta|2^k(sta\And 2^k=0)}\),转移系数为 \(C(f_{key_i}-2-sta,2^k-1)\times 2^k!\),因为有 \(f_{key_i}-1\) 个“垫材”,但要除去 \(1\) 即我,还要除去已有的子树的占用人数,特别的是,这里 \(sta\) 的值恰为其占用的人数,因为位权为 \(2^k\) 的位恰好对应着 \(siz=2^k\) 的子树。然后内部可以随意排列。
-
-
-
最后乘上 \(2^n\),因为从最左边两个 \(siz=2^0\) 到最大的两个 \(siz=2^n-1\) 的子树都可以互相换位。
-
复杂度为 \(O(nm\times 2^n)\),那这样已经有 50pts 了。
-
考虑引入 \(k\neq 1\)。
-
一个自然的想法是将 \(sta\) 推广成当前的 LIS 情况,当然,这一情况需要是可转移的,故应当是把一个求 LIS 的 dp 套进来。
-
换言之,我们希望记录一个 \(sta\),其为一个向量,具体地,\(sta_j=dplis_j\)。
-
若将这些状态向量视为点,则其间有二元边 \((v,to)\),这里 \(v\) 表示在后面加的一个元素的值。
-
将该 DFA 建出然后跑自动机上 DP 即可,之所以必须提前建出是因为有 \(m\) 次一模一样的转移。
-
唯一的问题在于内层求 LIS 的 dp 怎么做,显然其需要是半在线的。但传统的求最长上升子序列算法,不管是结尾导向法还是长度导向法,都绕不过一个问题:他们的序列是静态的。
-
考虑使用对称的长度导向法,即“定大小插位置”即可。
-
-
复杂度为 \(O(msta\times n)\),容易猜到合法的状态向量不多,暴搜建出 DFA 后发现状态数只有 \(2\times 10^5\) 左右。随意咯~。
P8352 [SDOI/SXOI2022] 小 N 的独立集
-
题意:给定一棵 \(n\) 个点的树,所有点的点权在 \([1,K]\) 中,求最大权独立集的权为 \(1\sim nK\) 的方案数。
-
数据范围:\(n\leqslant 10^3,K\leqslant 5\)。
-
首先容易想到许多模糊不清的 dp 设计,其问题基本都集中在求的是 \(\sum\limits_T ways_j\),这里 \(T\) 是树,\(ways_j\) 是在对应树下的,权值为 \(j\) 的,在一般最大权独立集 dp 方式下求得的方案数。究其原因,一个求使某棵树的最大权独立集满足某些性质(权值,以及根节点选取与否)的树的权值分配方案数的 dp 和求一个确定树的最大权独立集的 dp 是极不同的,而我们的思维惯性将我们引向了错误的结果。
-
然后我又想到了不少看起来真一些的 dp,例如“\(dp_{i,0/1,j}\) 表示考虑了以 \(i\) 为根的子树,在选/不选 \(i\) 的前提下,使得对应子树的最大权独立集为 \(j\) 的对应子树的权值构造方案数。可以看出,这一 dp 并不直接指向 \(ans\),因为最后我们并不知道每种构造方案是选 \(1\) 大还是不选 \(1\) 大;但只有设计成这样我们才能转移,而在 \(1\) 那里,我们会用一点特殊的转移。”,这玩意的错误在于没法转移——\(dp_{i,0}\) 需要 \(dp_{son,\text{爱选不选 son 的前提下}}\),然而这个东西又是没法 dp 的...
-
我们发现,上面的引号里提到的“我们并不知道每种构造方案是选 \(1\) 大还是不选 \(1\) 大”是一个很尖锐的问题,这代表着我们不知道每个构造方案对应的真实最大权独立集的权值,然而事实上直接做这个权值 dp 也是做不到的。
-
考虑退一步,将简单树上最大权独立集 dp 套进去,设计如下 dp:
-
状态设计:\(dp_{i,j,k}\) 表示 \(i\) 的子树中不含 \(i\) 的最大权独立集权值为 \(j\),含 \(i\) 的的权值为 \(k\) 的方案数。这里比较特殊的在于原 dp 的转移可以 \(O(1)\) 求得,故并无必要实际建出 DFA。
-
初始化:\(dp_{i,0,1\sim K}=1\)。
-
状态转移:\(dp_{i,j,k}\times dp_{son,l,m}\to dp_{i,j+\max(l,m),k+l}\)。
-
-
乍一看是 \(O(n(nK)^4)\) 的,但注意到这本质上还是个树上背包,其上界应该不超过 \(O(n(nK)^3)\)。实践中可以过 \(n=100\)。
-
考虑进一步优化,显然这个 \(j,k\) 太炸了...由于背包性,只要能砍掉其中一个,问题其实就解决了。
-
考虑转定义。我们知道树上最大权独立集有一个经典的...怎么说呢?小代码习惯?是可以在求完 \(f_{i,0/1}\) 表示不选/选之后令 \(f_{i,1}=\max(f_{i,0},f_{i,1})\),此时 \(f_{i,1}\) 的定义变成“爱选不选 \(i\) 的最大权独立集权值”。类似地,我们在这里也可以转定义,然后记录差值!
-
显然,\(k\leqslant K-1\),等号在只有一个儿子,本节点权值为 \(K\),儿子节点权值为 \(1\) 时取到,这里我们显然可以不考虑儿子子树的干扰,其只会让 \(j'\) 更小。具体地,设计如下 dp:
-
状态设计:\(dp_{i,j,k}\) 表示 \(i\) 的子树中强制不包括 \(i\) 的最大权独立集权值为 \(j\),最大权独立集权值为 \(j+k\) 的对应子树的权值构造方案数。
-
初始化:\(dp_{i,0,1\sim K}=1\)。
-
状态转移:\(dp_{u,j,k}\times dp_{v,l,m}\to dp'_{u,j+l+m,\max(j+l+m,j+k+l)-(j+l+m)}\)。
-
-
于是我们的状态变成 \(O(nK^2)\) 的,感性理解发现总复杂度应该在 \(O(n^2\operatorname{poly}(K))\) 左右,足够通过本题。记得判一下,不做从 \(dp=0\) 出发的转移,可以大大减小常数。
P4590 [TJOI2018] 游园会
-
题意略。
-
很自然的一个想法是,把一个求 LCS 的 dp 拉过来各种魔改来计数。这里不再赘述,请移步线性 DP 查看(其实我自己也跑过去看了,乐)。
-
唔,我首先想到了非常典的假做法(先不管不能有
NOI
的限制,那显然是辅助维解决)...譬如 \(dp_{i,j,k}\) 表示构造的串构造了 \(i\) 位,考虑了已有串的前 \(j\) 位/LCS 在已有串的第 \(j\) 位结束,LCS 的长度为 \(k\) 的方案数。为什么假呢...因为这里的 \(k\) 并不真的是 LCS 长度,而是“按照这一 dp 的形式,所认为的一个长度”。更具体的解释的话...当 \(i+1\) 时,如果我认为它不在 LCS 中,则后面的构造必须满足一定的条件来使得它进入 LCS 至少不更优,然而这是无法体现在这个 dp 里的。 -
嘶。觉不觉得看到这里既视感很强?那就对了。上一道题中,我们也犯过类似的错误:所定义的值其实是对应 dp(非计数 dp)所认为的值,而不是真实值。解决办法则是把对应的 dp 整个压进状态里...唔...我们试一试。
-
考虑用哪个 dp 作为基底。我们先不考虑转为 LIS。显然,bitset 优化在这里应该没啥意义,何况我也不会。结尾导向法...这一做法的优势在于它是短方 log 长,但是这里我们显然不可能把构造串当成那个要 find 的串,故先不考虑它;我们转而考虑长度导向法。
-
首先我们得把长度导向法推广到在线情况...我指的是有一个串在线的情况。不妨把这个在线串放到第一维也即 \(i\) 上,记 \(f_{i,j}\) 为考虑完构造串(这里构造串是确定的)的前 \(i\) 位,已有串的前 \(j\) 位,当前的 LCS 长度为多少。这个 dp 的拓扑序是...额,摊到二维平面上就是依赖左下方矩形,一般的转移中我们直接从小到大依次枚举两维即可,这里我们也可以把 \(i\) 放在外面枚举来解决问题,转移时只依赖 \(f_{i-1}\),于是这个 dp 的状态可以用 \(f_i\) 的向量来等效,显然我们可以舍弃掉 \(f_{i,0}\)。
-
暴搜发现本质不同的 \(f_i\) 向量只有至多 \(5000\) 种左右,考虑到转移在建出 DFA 后可以 \(O(1)\),这一做法是 promising 的。故设计如下 dp:
-
状态设计:\(dp_{i,0/1/2,sta}\) 表示当前考虑完构造串的前 \(i\) 位,上一个是不是
N
(是对应 \(1\))或上两个是不是NO
(是对应 \(2\)),当前 \(f_i\) 的向量为 \(sta\) 的方案数。 -
初始化:\(dp_{0,0,0}=1\),这里第二个 \(0\) 是状态向量的零元。
-
状态转移:直接暴力枚举下一位,然后判一下辅助维,利用建出的 DFA 暴力转移。
-
-
总复杂度 \(O(nsta)\),6s 时限忽略一切常数,显然能过。实际实现中我把辅助维也压进了状态,发现一个有趣的事情:状态数几乎完全没变,与预想的翻三倍形成了不小的反差...
-
本题的状态还有一种理解:显然 \(f_i\) 单调递增,故考虑维护其差分数组,注意到差分数组是个零一数组。当然直接这样状压的效果可能比较差,因为空状态可能较多。
LOJ6274 数字
-
题意略。显然非常无从下手...
-
不妨考虑一个退化的问题:合法 \((x,y)\) 对计数。这一 dp 是容易的...注意到本题不具备可差分性,故设计如下 dp:
-
状态设计:\(dp_{i,sta}\) 表示考虑了二进制下高 \(i\) 位,当前的限制状态为 \(sta\)(一个二进制状态,对应位为 \(1\) 表示仍然受限,从高到低依次是 \(R_x,L_x,R_y,L_y\)),有多少种合法 \((x,y)\) 对。
-
初始化:\(dp_{i+1,11111111}=1\)。
-
状态转移方程:\(dp_{i,sta}=\sum\limits_{statr=0}^3 dp_{i-1,valid(sta,statr)}\)。这里 \(statr\) 是转移中填的 \(01\) 情况,也即第 \(i\) 位的 \(01\) 情况,\(valid(sta,statr)\) 是一个限制状态(指 \(sta\))的集合,其为弱到能够能在第 \(i\) 位上填 \(statr\) 且填了之后恰变换到 \(sta\) 的所有限制状态的集合。
-
-
这不太直观。让我们打开天窗说亮话吧:
-
该 dp 的 DAG 或者说 DFA 是一个分层图,有一个超级源点 \((i+1,11111111)\),除超级源点所在的层也即第 \(i+1\) 层之外,每层有 \(2^4\) 个点。
-
层间连边,边分四种(按 \(statr\)),边权均为 \(1\)(注意可能会有重边)。
-
边的可行性取决于对应的 \(T_i\),这里指的是二进制下第 \(i\) 位,边的存在性则取决于 \(L_i,R_i\)。
-
-
那么问题很简单了,我们建立一个新的自动机。
-
这个自动机上的点可以被描述为一个向量,其中含的是当前可以在前述自动机上的哪些点,某种意义上可以认为是在前述自动机上多路并行,但需要保证总是在同一层,通过这种方式避免退化到求所有路径的指数级复杂度。
-
状态数至多在 \(2^{16}\),转移的话容易暴力预处理,将所含的每个状态的某类出边指向的点集并起来就是从本点集走某类边将要走向的点集。
-
然后跑新的自动机的 dp,末端求和即为答案,当然也可以认为是在新自动机上建立超级源汇。
-
-
分析一下复杂度。
-
暴力构建原自动机的复杂度在...状态数 \(2^4\times n\)(\(n\) 为 \(T,L,R\) 二进制下位数),从每个点出发暴力枚举出边为 \(2^2\),即使考虑到计算转移终点的代价,不妨认为是 \(4\) 因为要逐位考虑,这一部分也就在 \(2^8\times n\) 左右。
-
然后是暴力构建新自动机,状态数 \(2^{16}\times n\),从每个点出发暴力枚举出边为 \(2^2\),枚举所含元素 \(2^4\),从元素找到对应出边然后将它们合起来为至多 \(2^4\),故单点的建边复杂度为 \(2^2(2^4\times 2)=2^7\),于是这一部分在 \(2^{23}\times n\) 左右。
-
之后在这个上面跑 dp,总边数为 \(2^{18}\times n\),故 dp 的复杂度也就这么高。
-
-
另一种有趣的做法是利用 \(x,y\) 的平等性来做剪除转移优化,类似 \(\text{CF1572C Paint}\) 那样。
-
仍然沿用 \(dp_{i,sta}\) 的状态,我们来对 \(10\) 和 \(01\) 做分讨:
-
不妨取 \(x\) 来推一下。\(x\) 既能填 \(0\) 又能填 \(1\),说明 \(L_{x,i}=0\) 和 \(sta_2=0\) 两者必居其一,同理 \(R_{x,i}=1\) 和 \(sta_3=0\) 两者必居其一。于是如果 \(x\) 填 \(0\),一定转到一个 \(sta_3=0\) 的状态,反过来一定转到一个 \(sta_2=0\) 的状态。这些结论对 \(y\) 对称成立。
-
给出结论:\(to_{sta,10}\) 和 \(to_{sta,01}\) 一定构成包含关系。所谓一定构成包含关系,是指一定有一者包含另一者。所谓包含,指的是...一者在后续过程中的转移路径完全包含了另一者的转移路径。
-
形式化地,将 \(To_{sta,10}\) 和 \(To_{sta,01}\) 记为对应状态下的所有合法 \((x,y)\) 对(注意这里的合法不考虑高位,且可能已经解除了某些限制)构成的 \(x\And y\) 集合,则一定有一者包含另外一者。不妨记为 \(A,B\),于是我们只需要证明 \(A-A\cap B=\varnothing\) 或 \(B-A\cap B=\varnothing\),换言之,\(\nexists (x\And y)_1 \And (x\And y)_2,\text{s.t.} (x\And y)_1 \notin B \And (x\And y)_2 \notin A\)。
-
我证明不到一块去。分讨太多了,而且关键是我没找到办法。
-
这一做法可能是出题人所没有预料到的,复杂度 \(O(2^5\times n)\),可以做非常大的高精范围。我偷个懒,写这个了。
-
-
23.2.33 upd:一个更一般化的理解是,不妨考虑对于确定的 \(x\And y\) 怎么判定可行,遂得到一个自动机,注意该自动机并不真地关心每一位上的限制,而是只关心对应的算符(即只关心在吃到了什么类型的边,会导致满足条件的情况发生什么变化)。将该 dp 套进去,然后注意到有时会同时处在该自动机上的多个点,不过该自动机也很小(\(2^4\) 而已,因为和 \(i\) 无关),所以将其再状压起来。
P8497 [NOI2022] 移除石子
-
题意略。我们首先考虑一个退退化版的问题:给定石子序列,\(K=0\),是否可以获胜。
-
有一个很自然的想法:尽量用操作一,然后把操作二调整上去,操作二的出现一定是为了处理 \(a=1\)(当然可能是被操作二了一些之后才为 \(1\) 的)。由小凯的疑惑,我们可以规定只会对长为 \(3,4,5\) 的区间进行操作,且每个区间被操作的次数一定是 \(0/1\),否则可以换成区间操作一。于是考虑设计 dp 如下:
-
状态设计:\(f_{i,j,k,l}\) 表示令 \(1\sim i\) 都为 \(0\),以 \(i\) 结尾的长为 \(1\) 的区间有 \(j\) 个,长为 \(2\) 的区间有 \(k\) 个,长为 \(3\) 及以上的区间有 \(l\) 个。虽然我们说可以只用 \(len\in [3,5]\),但当 \(4,5\) 反而增大了我们的复杂度的时候,它们就没啥意义。
-
初始化:\(f_{0,0,0,0}=1\)。
-
状态转移:从 \(f_{i,j,k,l}\) 出发,枚举 \(x\) 表示在 \(i+1\) 处要创建多少个区间,枚举 \(y\in [0,l]\) 表示要继续延伸的长为 \(3\) 及以上的区间有多少个,然后转移到 \(f_{i+1,x,j,k+y}\) 处,当且仅当 \(a_{i+1}-x-j-k-y\) 为 \(0\) 或大于 \(1\) 时合法。
-
考察各维大小和枚举量,这时 \(len\in [3,5]\) 用处就大了。\(j,k,x\in [0,3]\),\(l\) 的话...以 \(i\) 结尾且长度为 \(3\) 及以上的区间至多有 \(3\) 个,但其中至多有两个有资格继续延伸,故我们其实可以把 \(l\) 的定义改成“还要继续延伸的,长为 \(3\) 及以上的区间有 \(l\) 个”,于是 \(l\in [0,2],y\in [0,l]\),但这样一来转移时还要枚举一个 \(z\) 表示原有的长为 \(2\) 的区间在现在长度变成 \(3\) 后还是否打算继续延伸...一团乱麻。
-
-
抓住核心。抓住同构状态。什么是钦定 \(l\) 还要继续延伸?实质为至少还要延伸一格。那么此时 \(k,l\) 并没什么区别!转而设计如下 dp:
-
状态设计:\(dp_{i,j,k}\) 表示令 \(1\sim i\) 都为 \(0\),至少还要向前延伸两格的区间有 \(j\) 个,至少一格的有 \(k\) 个,是否可行。因为我们刚才推导的核心并不是已有几格而是还要走几格,所以转定义成还要延伸多少的同构状态比较方便。
-
初始化:\(f_{0,0,0}=1\)。
-
状态转移:从 \(f_{i,j,k}\) 出发,枚举 \(x\) 为新建区间数,\(y\) 为继续延伸的区间数,转移到 \(f_{i+1,x,j+y}\),当且仅当 \(a_{i+1}-x-j-k\) 为 \(0\) 或大于 \(1\) 时合法。
-
考察各维大小和枚举量。\(j,x\in [0,3]\),\(k\)...被迫延伸的最多 \(3\) 个,选择延伸的最多 \(2\) 个,故 \(k\in [0,5]\) 即可。
-
结论:从 \(i\) 没必要同时发出 \(4,5\),其可以变成 \(i+1\) 发出 \(3,4\)。
-
如果 \(i+1\) 本来在发出 \(3\),那么该情况非最简,可以变成仅从 \(i+1\) 发出 \(4\)。
-
如果 \(i+1\) 本来在发出 \(4\),那么该情况非最简,可以变成仅从 \(i+1\) 发出 \(3\)。
-
如果 \(i+1\) 本来在同时发出 \(3,4\),那么该情况非最简,可以变成什么都不发。
-
-
故从 \(i\) 出发最多同时发出两个区间,\(j,x\in [0,2]\),\(k\) 中被迫的最多 \(2\) 个,选择的最多 \(1\) 个,\(k\in [0,3]\)。
-
结论:\(k\) 中不可能同时有两个被迫和一个选择。即,\(k\in [0,2]\)。
- 此时一定是被迫为 \([i-2,i+1/i+2]\),选择为 \([i-3,i+1]\),但其可以简单拆成 \([i-3,i-1]\) 和 \([i,i+2]\)。
-
至此,优化完毕。时间复杂度...大概是 \(O(54n)\),说是大常数 \(O(n)\) 也对...最后结果为 \(f_{n,0,0}\)。
-
-
我们接下来可以做一个 \(O(Kn)\) 的 dp,毕竟容易证明某堆石子被加的量一定为 \(0\) 或 \(1\),足够获得 40pts。正解看起来像是把这个 \(O(Kn)\) 的 dp 套进去(有意义的石子数仅有 \(0\sim 7\) 和 \(8\),更大的都是 \(8\)),但显然状态数太多了没法接受。
-
这肯定是明示我们 \(K\) 有性质。尝试分析:
-
恰好 \(K\) 个是不好做的,我们设法将之转化为不超过 \(K\) 个,但显然这不是等价变换。考虑考察哪些情况不等价。
-
显然 \(K=0\) 无所谓。
-
对于 \(K=1\),考虑 \(K=0\) 的所有方案:
-
若有操作 \(1\) 则直接放上去。
-
否则,若有长大于 \(3\) 的操作二则放到端点上然后拆成一+二。
-
否则,若有长恰为 \(3\) 的操作二,则尝试将之延长。
-
三者都不成立,当且仅当什么操作都没有即 \(a=0\),或者只有一个长为 \(3\) 的操作二且无法延长即 \(n=3,a=1\)。
-
-
对于 \(K=2\):
-
若 \(K=0\) 有解则随便放哪里操作一一次。
-
若 \(K=1\) 有解,则条件同 \(K=1\) 在 \(K=0\) 的方案上的变换。但显然加了一颗石子后"三者都不成立”则加之前也无解(对应的 \(K=1\) 也无解),故若 \(K=1\) 有解则一定有解。
-
综合起来即若 \(K<2\) 有解则 \(K=2\) 有解。
-
-
注意到这里 \(K=2\) 对 \(K=1\) 的依赖非常有趣,它是闭合的。考虑归纳,发现对于 \(K>1\),若 \(k<K\) 有解,则 \(K\) 有解。
-
-
由此,考虑转而设计一个解性 dp,具体地,对于一个确定的序列 \(a\),我们希望知道它至少需要加多少石子才有解。如果最后求出来的结果是 \(0\) 那么需要对 \(1\) 特判,否则平凡,这个 dp 的设计如下:
-
状态设计:\(g_{i,j,k}\) 表示令 \(1\sim i\) 都为 \(0\),至少还要向前延伸两格的区间有 \(j\) 个,至少一格的有 \(k\) 个,至少需要多少石子才可行。
-
初始化:\(g_{0,0,0}=0\)。
-
状态转移:仍然枚举 \(x,y\),然后对 \(a_{i+1}-x-j-k\) 分类讨论,若其为负数则需要额外的绝对值个,否则若为一则需要一个,否则不需要。
-
显然这一 dp 的时间复杂度也为 \(O(n)\),需要的石子数在 \(g_{n,0,0}\) 处取得。
-
-
接下来考虑把 \(g\) 套进去来计数,具体地,设计如下 dp:
-
状态设计:\(F_{i,sta}\) 表示考虑了前 \(i\) 位,\(g_i\) 为 \(sta\) 的方案数,这里 \(sta\) 是一个长度为 \(9\) 的向量,方便起见进制编码一下。
-
初始化:\(F_{0,\text{g 的初始化}}=1\)。
-
状态转移:暴力枚举 \(a_{i+1}\),当然只枚举有意义的取值,然后带权地转移到 \(F_{i+1,trans(sta,a_{i+1})}\),这里因为转移和 \(i\) 无关所以应当预处理或记忆化。
-
最终答案即为 \(\sum\limits_{sta} F_{n,sta}\times valid(K,sta_{0,0})\)。这里 \(valid(x,y)\) 是判断是否可行的函数,\(valid(x,y)=\begin{cases} x\geqslant y & y>0 \text{ or } x\neq 1\\ check(a) & \text{else}\end{cases}\),这里 \(check(a)\) 即我们之前提到的对 \(K=1\) 的特判。
-
问题在于合法的状态数有多少种。首先可以打表发现 \(\geqslant 6\) 的 \(a\) 都相当于 \(6\),事实上通过考察单点至多会被多少个区间覆盖的话,会发现至多被 \(3\) 个区间覆盖(不考虑其他剪枝的影响),从而得到一个更紧的界为 \(5\),但这个剪枝不能再加,因为我们不能同时满足我们已有的剪枝和这个界,而在已有的剪枝下证明这个结论并不容易,大体上基于“如果有很多还要延长的区间,则在这里开区间不必要”。
-
由此,在规定 \(g\) 的取值不超过 \(101\) 的前提下,暴搜可得 \(sta=8765\),建出 \(g\) 的 DFA 后(因为转移与 \(i\) 无关)可以近似 \(O(1)\) 转移,于是总复杂度也就只是大常数 \(O(Tnsta)\),所以已经足够通过本题。
-
P5279 [ZJOI2019] 麻将
-
题意略。其实做过移除石子之后这道题也不那么难...
-
首先考虑建出胡牌自动机,点为手里有的十三张牌,边为摸到的牌。不妨直接从题目给出的起始状态开始来搜。注意该 DFA 是有终止节点的。
-
所有排列等概率出现,等价于每次抽到每张牌的概率均等。直接暴力枚举之,复杂度为 \(O((4n-13)^2STA)\),这里 \(STA\) 是多路并行的状态。随便假。
-
这一做法的问题在于,随着抽牌过程的行进,抽到每张牌的概率不再均等,因为有一些概率跑到 \(null\) 去了。不妨假设第一手抽到 \(x\) 的都转移到 \(null\) 去了,因为 \(null\) 不能做转移起点,所以现在其他牌的概率被摊薄了一些但 \(x\) 的没有,现有概率中 \(x\) 一定还没被摸出来。
-
故我们不能搞多路并行。我们一直把牌拿在手里,不弃,然后设法判断子集。
-
那么老套路,考虑一个子问题:给定一个手牌集合 \(S\),判断是否存在 \(s\in S(|s|=14)\) 满足 \(s\) 胡了。首先方便起见我们肯定是维护一个长为 \(n\) 的向量,\(sta_i\) 表示第 \(i\) 种牌有多少张,于是七对只需要扫一遍解决即可,我们只判断是否存在四面+一对。设计 dp 如下:
-
状态设计:\(f_{i,j,k,l}\) 表示考虑了前 \(i\) 种牌,当前有 \(j\) 个对子,当前未完成的还需 \(1,2\) 张的顺子各有 \(k,l\) 个,最多有多少个面子。为了转移方便起见,我们规定它如果有多的牌则必须尽量花完。这其实是 CF1110 D。
-
初始化:\(f_{0,0,0,0}=0\)。
-
状态转移:可以在 \(i+1\) 处构造对子,刻子,延长(结算)顺子。注意可能前两者能和第三者同时进行。具体地,对 \(a\) 分类讨论:
-
\(a=1\):仅延长顺子,显然优先挑长的延长。故若 \(k\) 则转移到 \(f_{i+1,j,0,0}\) 且 \(+1\),否则若 \(l\) 则转移到 \(f_{i+1,j,1,0}\),否则转移到 \(f_{i+1,j,0,1}\)。
-
\(a=2\):仅延长顺子或构造对子,延长连续型一模一样不说了,构造对子是转移到 \(f_{i+1,1,0,0}\)。
-
\(a=3\):仅延长,延长且对子或刻子。有点多不写具体转移了。
-
\(a=4\):仅延长,延长且对子或延长且刻子。同上。
-
-
注意,任何时候 \(f_{i,1,x,y}=4\) 则直接结束。更大的值我们都认为是 \(4\)。
-
考察各维大小,注意到相同的三个顺子相当于三个刻子,故 \(k,l\in [0,2]\)。
-
-
唔,看起来还不错...但是这个 DFA 看起来很怪,它是一种牌一种牌地往里加的...哦哦。各种牌是没有区别的。那么我们有一个自动机了,这个自动机的点是一个 \(f\) 的值的向量(将 \(j,k,l\) 编码起来),\(\delta\) 是读取下一种牌的数量来转移的,唯一的问题是这个自动机本身处理不了七对,所以我们要在向量上额外挂一个已有的不同对子数量。注意任意的 \(f_{1,x,y}=4\) 或者挂的对子数量为 \(7\) 则该点都应当为 \(null\)。
-
显然想要一张一张地摸对于这个 DFA 是不现实的,故这里需要用到一个经典的变换:期望次数=1+摸了一次没成功的概率+摸了两次没成功的概率+摸了三次没成功的概率+...,最开始的 \(1\) 是因为无论如何要摸一次,后面的每个其实都相当于“摸了 \(k\) 次还不够,还要至少再摸一次的概率”。
-
这有什么好处呢?这就使得我们的摸牌过程变成了无序的。换言之,如果摸了 \(k\) 次还没成功,那么这 \(k\) 次以及初始的手牌都是无序的,我们可以把它们按花色顺序添加进来!设计如下 dp:
-
状态设计:\(F_{i,j,k}\) 表示考虑了前 \(i\) 种花色,当前一共摸了 \(j\) 张牌(将初始牌视为必摸牌),当前在前述自动机上 \(k\) 点处的方案数。
-
初始化:\(F_{0,0,0}=1\),这里最后的 \(0\) 为该自动机的 \(S\),即 \(f\) 的初始化。
-
状态转移:暴力枚举下一个花色会有多少张(注意需要考虑初始牌),然后转移即可。实际实现可能需要滚动数组。
-
-
最后求答案时应为枚举 \(j\),找到所有 \(k\neq null\),将其概率乘以 \(\frac{(j-13)!(4n-13-(j-13))!}{(4n-13)!}\) 求和,然后加一即可。这里乘的前者表示非必摸牌摸到手里的顺序是随意的,第二者表示没摸到手里的牌的顺序是随意的,最后除就不用说啦,事实上这还是那个经典公式 \(E=\sum P(x)\times v(x)=\sum \frac{Cases(x)\times v(x)}{Cases}\) 的应用。
P4052 [JSOI2007] 文本生成器
-
题意略。还蛮符合我们的共性定义的嘛...但这里并没有所谓的内层 dp,内层套的是 KMP 字符串匹配算法,而其在多模式串下的自动机就是 AC 自动机...我大概得好好考量一下这些题目该怎么分类和提炼共性了。也许建自动机式问题应该称为建 DAG 优化,因为作用在于剪除无用状态...
-
如果文本串是已知的,那么我们只要在模式串的 AC 自动机上处理这个问题就好了,对 fail 树做一下处理把“这里有串结尾”的标记推下去,然后 dfs 一遍就解决问题。
-
考虑推广到不定的串。设计 dp 如下:
-
状态设计:\(f_{i,sta}\) 表示长为 \(i\) 的文本串当前在自动机上 \(j\) 处的方案数。注意我们这里的自动机不完全是 AC 自动机,任意串结尾点在 fail 树意义下的子树(包括它本身)都是 \(null\)。
-
初始化:\(f_{0,0}=1\)。
-
状态转移:暴力枚举下一个字符进行转移即可。
-
状态数 \(O(n|AC|=nm|s|)\),转移 \(O(|\Sigma|)\),总复杂度为 \(O(nm|s|\times 26)\to 1.56\times 10^7\),未免有些太松了。
-
P2414 [NOI2011] 阿狸的打字机
-
题意:预先给出全部 \(n\) 个串 \(S_{1\sim n}\),然后给出 \(Q\) 组询问,每个询问形如“\(S_x\) 在 \(S_y\) 中出现多少次”。后面称 \(S_x\) 为模式串 \(P\),\(S_y\) 为文本串 \(T\)。
-
数据范围:\(n,Q\leqslant 10^5\)。使用特殊方式给出模式串,保证 \(|AC|\leqslant 10^5\)。
-
发现这里的主要特点在于我们预先知道所有串,题目的输入方式也在暗示我们把所有串都插进 AC 自动机。显然用一般的 AC 自动机上模式串匹配会 T 飞,故肯定有性质。注意到“文本串也是模式串”。
-
故考虑从 AC 自动机的结构出发。fail 操作的本质是舍弃尽量短的非空前缀,换言之 \(fail_i\) 对应的字符串一定是 \(i\) 的一段真后缀,这代表着 fail 树上一个点子树内的点都为该点在 trie 树上对应的字符串加上任意长前缀(因为我们把子树的根也视为在子树内,故加的前缀不一定非空)。有趣的是 trie 树的子树性质恰好反过来。
-
由此考虑到将 \(T\) 在 trie 树上的表现(一条链)拉出来,若其上某个点 \(T_{1\sim i}\) 在 fail 树上 \(P\) 的子树内,则代表着 \(T_{1\sim i}\) 的一段后缀为 \(P\)。
-
问题转化成求 trie 树上一条链,即从 \(0\) 到 \(S_y\) 即 \(T\) 结尾,和 fail 树中一个子树,即 \(s_x\) 即 \(P\) 结尾的子树,的交集大小。注意这里虽然我们不用 AC 自动机(我指的是 trie 图),但是还是需要 build,因为没有很好的方式可以不建 trie 图而建出 fail 树。
-
这个问题我们使用基于欧拉环游序的 dfs 来解决:
-
考虑上 trie 树跑 dfs。我们在进入某个点时,将该点赋值为 \(1\);退出时赋值为 \(0\)。
-
于是只有链上的点有值。把询问挂到链尾,在链尾赋值完毕之后,对该询问的子树做求子树和,子树和即为答案。
-
子树和的实现这里采用了用 dfn 序和树状数组。
-
-
总复杂度 \(O((|AC|+Q)\log |AC|)\)。这纯粹是深挖 AC 自动机的性质啊...显然这和上面几个并不相同...我不是能很好地把握到它们的异同。
[AGC055C] Weird LIS
-
题意略。好怪的一道题...
-
不妨先假定 \(a\) 是已知的,考虑检验其合法性。显然 \(a\) 的取值只会是 \(|LIS|\) 或 \(|LIS|-1\)。
-
经过一段时间的完全没思路(试了一下再退一步把 \(p\) 也固定,然后发现我甚至固定 \(a,p\) 检验合法性都不会...想到的最好做法是建图,拓扑排序最长路计数,正反处理一下求支配点),看了一下 Legitimity 的题解(格式稍作了调整,并做了一些不影响核心意思的修改):
-
不妨设 \(|LIS(p)|=k\),对 \(p\) 定义必经点、非必经点、无用点:
-
若位置 \(i\) 在所有 LIS 中,即去掉位置 \(i\) 后 LIS 长度减少,那么称 \(i\) 为必经点,有 \(a_i=k-1\)。
-
若位置 \(i\) 在某个 LIS 中,且去掉位置 \(i\) 后 LIS 长度不变,那么称 \(i\) 为非必经点,有 \(a_i=k\)。
-
若位置 \(i\) 不在任何一个 LIS 中,那么称 \(i\) 为无用点,有 \(a_i=k\)。
-
-
首先我们考虑整个 \(A\) 序列都是一种值的情况。
-
全都是 \(k-1\),即全是必经点。显然满足条件的只有 \(k=n\) 时 \(p=\{1,2,\ldots,n-1,n\}\)。
-
全都是 \(k\)。注意到非必经点一定是成集合出现,当集合中的某个点被删掉,其余点能发挥等效的作用(故集合大小至少为 \(2\)),即一个集合对 \(k\) 产生 \(1\) 的贡献,那么可得 \(n\) 个非必经点至多产生 \(\lfloor\dfrac{n}{2}\rfloor\) 的贡献,必要条件就是 \(k\leqslant \lfloor\dfrac{n}{2}\rfloor\),这个序列由 \(x\geqslant 2k\) 个非必经点和 \(n-x\) 个无用点构成。这个条件也是充分的,考虑形如(这里我觉得原有构造不对)\(p=2,1,4,3,6,5\) 的构造,可以取得 \(\lfloor\dfrac{n}{2}\rfloor\),然后按需调大某些集合的大小即可。
-