AC自动机配合普通DP,状压DP,矩阵,Fail树等使用较多
普通AC自动机:
1.题目大意:给定一个n*m的矩阵,再给定k个串,求每个串最早出现的位置
题解:为每一个方向建立AC自动机并且匹配。
2.题目大意:求有多少串s出现在t中,并输出这些串
题解:为每个t建一个AC自动机并匹配
3.题目大意:求每个串s在t中出现次数
题解:一种可以开128个儿子直接匹配,但时间空间太浪费,可以只开26个,遇到非字母直接把当前节点设为0
可以看出裸的一般都是有多个模式串,然后求出现位置,次数等,比较简单。
但ac自动机的匹配容易被卡。
AC自动机配合普通DP:
1.题目大意:给出一些不能出现的串s和当前串t,求最少修改多少的字母使得串中不出现那些s
题解:设f[i][j]表示到第i个字母,匹配到j最少修改多少字母
先用AC自动机预处理出每个点是否合法。
2.题目大意:有n个串s,每个串有一个价值,构造一个长度不超过m的串t,使得价值最大,输出这个字符串,要求t长度尽量小,之后字典序尽量小。
题解:用AC自动机预处理出每个点的权值
设f[i][j]表示到第i个字母,匹配到j的最大价值
则f[i][j]+w[son]->f[i+1][son]
这里要输出最小,于是我们可以考虑f[i][j]表示从i一直加到m的答案
在记一下从哪转移的,这样可以保证字典序最小
3.题目大意:给定n个串s和串t,要求重新排列串t,使得s在t中出现次数最大
字符集大小为4
题解:设A,G,C,T个数为A,B,C,D
设一个映射f(a,b,c,d)=a*(B+1)(C+1)(D+1)+b*(C+1)(D+1)+c(D+1)+d
以此映射作为状态,可大大减少时空复杂度
总结:AC自动机的DP一般要求多个串在一个串中达到某些要求,一般涉及到是否出现,且范围都较小。
AC自动机+状压DP
1.题目大意:有n个串s,构造一个长l的串t使得n个串都出现,求方案数
题解:设F[i][s][j]表示第i个字符,出现状态为s,匹配到第j个结点的方案数
预处理出每个结点的状态,直接转移
2.题目大意:有n个串s,构造一个长l的串t使得n个串中至少有k个出现,求方案数
题解:DP过程和上一题一样,统计答案多统计一点就行了。
总结:AC自动机的状压一般对出现情况作出一些要求,也不排除是题目本身有状压。
AC自动机+矩阵
1.题目大意:有n个串s,构造一个长小于等于l的串t,使得至少有一个s是t的子串,求方案数。
题解:转化成求一个都不包括的数量,建立AC自动机,若两个结点都合法,则连一条边,然后矩阵快速幂,相当于求Mat^1+Mat^2+…+Mat^n。
总结:一般s范围很小,t范围很大。
Fail树
Fail树是fail指针反向形成的树形结构。
在fail树中若串y中存在一个结点使得串x的末尾结点是它的祖先,则x是y的子串
1.题目大意:有n个单词,求每个单词在所有单词中出现的总次数。
题解:建出fail树,对于一个结点,他在fail树的子树的每一个结点都能匹配到这一结点,所以只需要知道有多少的串经过这一结点就可以了。
2.题目大意:有n个串s[i],q个询问每次询问s[x]在s[y]中出现了多少次
题解:离线处理,每次集中处理y相同的询问,对于每个x,只需求出子树中有多少个y的结点,可以树状数组解决
3.题目大意:给定n个串,每个串有个价值,在其中找出若干个串,使得按照输入顺序前一个串是后一个串的子串,求价值和的最大值。
题解:设f[i]为以i结尾的答案
则f[i]=max{f[j]+w[i]|j是i的子串}
考虑用i更新i后面的串的f值,则相当于区间修改子树,对应到dfs序上是一段连续区间,用线段树更新即可。
4.题目大意:有n个串s,一开始每个串的类型都为1,有m个操作,一种操作是讲一个串的类型设为0/1,另一种操作求所有类型为1的串在给定串中出现的总次数。
题解:第一种操作可以看成是dfs序上的区间加和区间减,第二种操作在AC自动机上匹配,每次单点查询,累加。
总结:若题目涉及到多次询问一个串是否是另一个串的子串,则可以考虑fail树