CF来到2600
题意
$T \le 5$ 组数据,给定 $n \le 10$ 个字符串,字符集为大、小写字母且每个字符在同一个串中最多出现两次,求它们的LCS(最长公共子串)
做题
暴力做法就类似两个串的LCS,直接 $10$ 维dp,时间……
发现有信息没用:字符集为大、小写字母且每个字符在同一个串中最多出现两次
先考虑如果每个字符只出现一次怎么办,由于字符集不大,可以考虑设计状态为 d[ch]
表示“以**字符 $ch$ **结尾的前缀子串的LCS”,方程明显为 $d[i] = \max(d[j]) + 1$ ,这里要保证在所有串中字符 $j$ 都在字符 $i$ 的前面,关于字符的位置可以预处理
现在,字符出现了两次,当然可以延续上面的做法,预处理字符的位置,把状态设计为“以字符 $ch$ 结尾的前缀子串的LCS”,但同时我们必须知道这个字符在每个串中是第几次出现,考虑状压,用一个二进制数 $s$ 表示在每个串中是第几次出现,则状态 d[ch][s]
表示“以字符 $ch$ 在第 $i$ 个串中第 $k_i$ 次出现结尾的前缀子串的LCS”,其中 $k_i$ 是 $s$ 中压缩的信息, $k_i = 0 / 1$ 表示第 $1 / 2$ 次出现
转移的时候有个贪心:可以从 $k_i = 1$ 转移就不必从 $k_i = 0$ 转移,因为第 $2$ 次出现一定在第 $1$ 次后面,以它结尾的前缀子串一定包含了第 $1$ 次,所以转移时,设当前转移为 $d[ch][s] \gets d[j][t]$ ,直线枚举字符 $j$ ,若在串 $i$ 中字符 $ch$ 前有两个 $j$ 就从 $k_i = 1$ 转移,有一个就从 $k_i = 0$ 转移,换句话说,我们在枚举 $j$ 时就确定了 $t$
考虑时间,设字符集大小为 $V$ 状态有 $V \times 2^n$ 个,每次转移要枚举字符 $j$ 并 $O(n)$ 得到 $t$ ,故时间为 $O(V \times 2^n \times V \times n) = O(V^2 2^n n)$
由于判断较多,具体实现可以考虑记忆化搜索
代码
稍微压了压行
1 |
|