\(\rm P1357\) 花园
首先思考朴素 \(\mathtt{dp}\)。设 \(dp_{i,j}\) 为前 \(i+m\) 个花盆,前 \(m\) 个花盆的状态为 \(j\) 的方案数。
最后对于每个初始状态 \(dp_{0,s}\),我们统计 \(dp_{n,s}\)。因为要保证初始状态相同。
我们发现状态转移和 \(i\) 没有什么关系,于是可以先 \(\mathtt{dp}\) 一个转移矩阵,第一维快速幂即可。最后取对角线也是为了初末状态相同。
\(\text{[SDOI 2009] HH }\)去散步
最困难的地方就是 “不会沿着来的路走回”。于是可以化点为边。
\(\text{POJ - 3420 Quad Tiling}\)
最开始的思路是设一个 \(2^8\) 的状态用来表示倒数 \(2\) 行的 \(\text{Domino}\) 摆放情况。但在转移的过程中,我们发现这是浪费的:因为若 \(s\) 能转移,它的倒数第二行必须全填满。所以其实转移只和倒数第一行的状态有关,我们将状态缩减至 \(2^4\)。
之后我们发现从 \(0000\) 开始不可能转移到某些状态,可以减到 \(6\)。
转移大概这样:
戳我!
state:
0. 0000
0000
1111
0011
1100
1001
1. 1111
0000
2. 0011
0000
1100
3. 1100
0000
0011
4. 1001
0000
0110
5. 0110
1001
\(\text{CodeForces - 1151F Sonya and Informatics}\)
考虑我们如何从初始状态转移到末状态。假设串中有 \(c\) 个 \(0\),末状态就是前 \(c\) 个是 \(0\),后 \(n-c\) 个是 \(1\)。如果我们将后 \(n-c\) 个中的 \(0\) 转移到前 \(c\) 个,我们称这种转移是有用的。而且你会发现 \(0\) 在前 \(c\) 个的任意位置都是等价的。
于是 \(\mathtt{dp}\) 就呼之欲出了:令 \(dp_{i,j}\) 为前 \(i\) 次操作,在前 \(c\) 个位置有 \(j\) 个 \(0\) 的方案数。答案就是 \(\frac{dp_{k,c}}{\sum_{i=0}^c dp_{k,i}}\)。
我们讨论交换字母是否在前 \(c\) 个,字母是否为 \(0\) 来 \(\mathtt{dp}\) 即可。\(k\) 特别大,需要矩阵加速。
\(\text{[HNOI 2010] }\)公交线路
先开始想设 \(dp_{i,j}\) 为填到第 \(i\) 位,把这一位填成 \(j\) 的方案数。但是假设枚举 \(dp_{u,j}\) 你会发现,\([u+1,i-1]\) 这一段根本没法计算。
我们最好用 一个整体 来转移 —— 观察得知,“一辆公交车经过的相邻两个站台间距离不得超过 \(p\)” 的限制其实等价于 “任意长度为 \(p\) 的区间内包含 \([1,k]\) 中所有数字”。
由此,我们想到状压。注意还需要满足所有格子都被填上了数,不妨设 \(dp_{i,j}\) 为前 \(i\) 个格子已经填满,\([i+1,i+p]\) 的状态为 \(j\) 的方案数(\(j\) 的第 \(i\) 位是从小到大数的第 \(i\) 位,第一位表示位置 \(i+1\))。我们并不需要刻意区别不同种类的数字,因为它们的不同已经被初始位置描述。
关于转移 \(s\rightarrow t\),首先保证 \(s\) 的第一位为 \(1\)。接着去掉第一位,在末位补上 \(0\) 得到 \(s'\)。当 \(s'\) 中 \(k-1\) 个 \(1\) 可以和 \(t\) 中 \(k\) 个 \(1\) 中的 \(k-1\) 个对应时即可转移。这相当于将第一位的 \(1\) 挪到后面。
因为保证每个状态第一位为 \(1\),实际状态数为 \(\text{C}(p-1,k-1)\)。注意实现要卡着这个数,否则会 \(\mathtt{T}\)。
「\(\text{THUSCH 2017}\)」大魔法师
比较难搞的是区间内部给内部改值。不妨将其改成矩阵,这样我们只用修改和合并改值的方式即可。