一类巧妙利用利用失配树的序列DP
I.导入
求长度为\(\text{len}\)的包含给定连续子串\(\text{T}\)的 0/1 串的个数。(\(|T|<=15\))
通常来说这种题目应该立刻联想到状压 DP 与取反集——这样就不用考虑大量重复情况的容斥问题。设\(f_{i,S}\)表示前\(i\)个字符、最后\(|T|\)个字符为\(S\)、不包含给定连续子串的情况数,状态转移方程简单不述。时间复杂度 \(\Theta(2^{|T|}\text{len})\)。
II.巧妙利用利用失配树的序列DP
上述算法的时间复杂度相当高昂,当\(\text{T}\)十分大或者不是一个 0/1 串而是一个字符串的时候完全不可做,并且大量的状态是无用的,因为我只关心不出现给定的字符串,然而相当多的状态不用转移已经注定了不可能出现给定字符串,用状态压缩表示表示整段的完整状态非常亏本。重磅的优化来了:
我们在 DP 状态的设置上模拟 KMP 算法的过程。设\(f_{i,j}\)表示前\(i\)个字母、已经匹配到了模式串的\(j\)时有多少种情况。那么状态转移也依照 KMP 算法:枚举当前点的\(j\)并枚举下一个点填的字符,在失配树上找到下一个点的\(j\),把\(f\)累加过去,时间复杂度\(\Theta(\text{len}|T|^2s)\),其中\(s\)是字符种类数。
当然不止可以在模式串上加强,还可以在文本串上加强:当\(\text{len}\)是天文数字的时候,我们完全可以用矩阵快速幂优化上述过程,时间复杂度是\(log\)的。
III.例一:诗人小 K

\(n \le 40\),\(1 \le x,y \le 5\),\(1 \le y \le 7\)。
反集转换肯定是要想到的,但是到了这一步后状态设置完全无法下手,三段的序列和你设什么状态都不是。注意到三段和的大小都非常小,连续的这么三段的长度的总数都非常少,总数只有\(2^{4+6+4}\)个。那么我们这些模式串全部枚举出来,问题就转化为不出现这些字串的字符串的个数。把模式串丢进一个 Trie 里面建出 AC 自动机,然后把每个终止点在失配树中的子树的结点都打上标记——不可转移,然后就跟上题一模一样了。
IV.例二:P3290 [SCOI2016]围棋
考虑这东西有了两列怎么办。我们使用一种巧妙的轮廓线 DP:设\(f_{i,j,S,x,y}\)表示到了点\((i,j)\)、轮廓线上的状态是\(\text{S}\)、当前行与模式串的第一行匹配到\(x\)、与第二行匹配到\(y\)时的方案数。轮廓线的状态由 0/1 组成,表示它的后缀是否能够与模式串的第一行完全匹配。状态转移方程显然,前两维可以滚动掉,后面的维度需要大量的 memset (大概二十亿?),所以还是会超时。解决办法是把所有变量和数组都放进 register,这样刷表的速度就可以上天。这种解法就是这题目前的最优解法了。
V.总结
处理包含一种模式串的字符串总数,应该转化为求不包含它的字符串数,这个问题可以用 KMP 的思想大大优化。
一类巧妙利用利用失配树的序列DP的更多相关文章
- BSOJ 5445 -- 【2018雅礼】树 prufer序列 dp
BSOJ在哪我也不知道 没有链接. 对于有标号无根树的统计和有度数限制 一般采用prufer序列. 根据prufer序列 容易知道 某个点的出现次数+1为当前点的度数. 对于这道题 考虑设f[i][j ...
- python利用Trie(前缀树)实现搜索引擎中关键字输入提示(学习Hash Trie和Double-array Trie)
python利用Trie(前缀树)实现搜索引擎中关键字输入提示(学习Hash Trie和Double-array Trie) 主要包括两部分内容:(1)利用python中的dict实现Trie:(2) ...
- 【字符串】【P5830】 【模板】失配树
[字符串][P5830] [模板]失配树 Description 给定一个长度为 \(n\) 的字符串 \(S\),有 \(m\) 次询问,每次询问给定 \(S\) 的两个前缀,求它们的最长公共 bo ...
- [Codeforces261D]Maxim and Increasing Subsequence——树状数组+DP
题目链接: Codeforces261D 题目大意:$k$次询问,每次给出一个长度为$n$的序列$b$及$b$中的最大值$maxb$,构造出序列$a$为$t$个序列$b$连接而成,求$a$的最长上升子 ...
- hdu 5909 Tree Cutting——点分治(树形DP转为序列DP)
题目:http://acm.hdu.edu.cn/showproblem.php?pid=5909 点分治的话,每次要做一次树形DP:但时间应该是 siz*m2 的.可以用 FWT 变成 siz*ml ...
- Codeforces Round #278 (Div. 1) Strip (线段树 二分 RMQ DP)
Strip time limit per test 1 second memory limit per test 256 megabytes input standard input output s ...
- hdoj5909 Tree Cutting(点分治+树上dp转序列dp)
题目链接:https://vjudge.net/problem/HDU-5909 题意:给一颗树,结点带权值v[i]<m.求异或和为k的子树个数(0<=k<m). 思路: 首先点分治 ...
- 72. Edit Distance(困难,确实挺难的,但很经典,双序列DP问题)
Given two words word1 and word2, find the minimum number of steps required to convert word1 to word2 ...
- 【bzoj4006】[JLOI2015]管道连接 斯坦纳树+状压dp
题目描述 给出一张 $n$ 个点 $m$ 条边的无向图和 $p$ 个特殊点,每个特殊点有一个颜色.要求选出若干条边,使得颜色相同的特殊点在同一个连通块内.输出最小边权和. 输入 第一行包含三个整数 n ...
随机推荐
- 脚本注入3(blind)
布尔盲注适用于任何情况回显都不变的情况. (由此,可以看出,回显啥的其实都不重要,最重要的是判断注入点.只要找到注入点了,其他的都是浮云.) 在操作上,时间盲注还稍微简单一点:它不需要像布尔盲注那样, ...
- 【UE4 C++ 基础知识】<12> 多线程——FRunnable
概述 UE4里,提供的多线程的方法: 继承 FRunnable 接口创建单个线程 创建 AsyncTask 调用线程池里面空闲的线程 通过 TaskGraph 系统来异步完成一些自定义任务 支持原生的 ...
- Netty学习笔记(2)ByteBuffer
1. 测试ByteBuffer 1.1 依赖 <dependencies> <dependency> <groupId>io.netty</groupId&g ...
- 移动端 h5 uniapp 读,写,删本地文件或sd文件
移动端 h5 uniapp 读,写,删本地文件或sd文件 应用场景: 当我们需要做离线应用或者是加载本地文件时使用到此方法.(本篇文章给大家分享访问app私有文件目录,系统公共目录,sd外置存储的文件 ...
- hystrix的配置说明
在我们的日常开发中,有些时候需要和第三方系统进行对接操作,或者调用其他系统的 api 接口,但是我们不能保证这些第三方系统的接口一定是稳定的,当系统中产生大量的流量来访问这些第三方接口,这些第三方系统 ...
- Linux下文件的三种时间标记:访问时间、修改时间、状态改动时间 (转载)
在windows下,一个文件有:创建时间.修改时间.访问时间. 而在Linux下,一个文件也有三种时间,分别是:访问时间.修改时间.状态改动时间. 两者有此不同,在Linux下没有创建时间的概念,也就 ...
- MySQL到底能否解决幻读问题
先说结论,MySQL 存储引擎 InnoDB 在可重复读(RR)隔离级别下是解决了幻读问题的. 方法:是通过next-key lock在当前读事务开启时,1.给涉及到的行加写锁(行锁)防止写操作:2. ...
- namaspace之pid namespace
认识Namespace namespace 是 Linux 内核用来隔离内核资源的方式.通过 namespace 可以让一些进程只能看到与自己相关的一部分资源,而另外一些进程也只能看到与它们自己相关的 ...
- jmeter 数据库压力测试之MySql
1.首先下载合适的数据库驱动:https://mvnrepository.com/artifact/mysql/mysql-connector-java 2.创建testplan,并添加jar包 3. ...
- Linux 系统分区方案 详细教程
简单分区方案 实际上,很多时候我们只需要分两个区:/和交换分区,日常使用基本不会有任何影响,甚至于交换分区对于现在的电脑来说都不是必要的,我们完全可以只分配一个根分区.linux只需要一个/根分区就可 ...