首页 > 其他分享 >【NOIP2013模拟联考8】匹配(match) 题解

【NOIP2013模拟联考8】匹配(match) 题解

时间:2024-03-13 22:22:56浏览次数:28  
标签:ac NOIP2013 int 题解 tail 母串 fail 自动机 联考

B 组都说看不懂……我也解释不清啊……只能写这么详细了

ac 自动机

ac 自动机上 dp


怎么才能判定一个母串是否包含几个模式串?

我们可以想到 ac 自动机,考虑对模式串建 ac 自动机,如果我们跑到了一个标记为 tail 的节点,说明我们的母串包含了这一个模式串。


所以我们设 \(f[i][s][j]\) 表示我们母串的长度为 \(i\),模式串的匹配状态为 \(s\)(状压后),当前母串跑到了 ac 自动机的节点 \(j\)。

我们枚举母串的第 \(i+1\) 个字符为 \(c\),然后在 ac 自动机上跑 \(j\) 的儿子 \(c\),再判断是否被标记为 tail,如果是,则对模式串的匹配状态 \(s\) 进行修改。

然后记得需要跳 fail

这些过程和 ac 自动机的匹配过程一模一样。


我们发现跳 fail 并不是线性的,所以我们需要优化它。

因为模式串很少,我们可以把跑到一个 fail 所有的模式串的 tail 状压起来

我们在建 fail 树时 tail[u] |= tail[fail[u]] 即可。

#include <cstdio>
#include <queue>
using namespace std;
#define N 110
#define M 32
#define K 8
#define P 1000000007
int n, m, k, cnt, ans;
char s[M];
int can[M];
int f[2][1<<K][N*M];
int nxt[N*M][26];
int tail[N*M];
int fail[N*M];
bool vis[26];
void insert(int x) {
	int p = 0;
	for(int i = 1; s[i] != '\0'; i++) {
		if(!nxt[p][s[i]-'a']) {
			nxt[p][s[i]-'a'] = ++cnt;
		}
		p = nxt[p][s[i]-'a'];
	}
	tail[p] |= (1 << x);
}
void build() {
	queue<int> q;
	for(int i = 1; i <= m; i++) 
		if(nxt[0][can[i]]) q.push(nxt[0][can[i]]);
	while(!q.empty()) {
		int p = q.front();
		q.pop();
		tail[p] |= tail[fail[p]];
		for(int i = 1; i <= m; i++) {
			if(nxt[p][can[i]]) {
				fail[nxt[p][can[i]]] = nxt[fail[p]][can[i]];
				q.push(nxt[p][can[i]]);
			} else {
				nxt[p][can[i]] = nxt[fail[p]][can[i]];
			}
		}
	}
}
int main() {
	scanf("%d %d", &n, &k);
	for(int i = 0; i < k; i++) {
		scanf("%s", s+1);
		insert(i);
	}
	scanf("%d", &m);
	m = 0;
	scanf("%s", s+1);
	for(int i = 1; s[i] != '\0'; i++) {
		if(!vis[s[i]-'a']) {
			vis[s[i]-'a'] = 1;
			can[++m] = s[i]-'a';
		}
	}
	build();
	f[0][0][0] = 1;
	for(int i = 0; i < n; i++) {
		for(int s = 0; s < (1<<k); s++) {
			for(int p = 0; p <= cnt; p++) {
				f[(i+1) % 2][s][p] = 0;
			}
		}
		for(int s = 0; s < (1<<k); s++) {
			for(int p = 0; p <= cnt; p++) {
				if(!f[i%2][s][p]) continue;
				for(int j = 1; j <= m; j++) {
					int pp = nxt[p][can[j]];
					(f[(i+1) % 2][s | tail[pp]][pp] += f[i%2][s][p]) %= P;
				}
			}
		}
	}
	for(int i = 0; i <= cnt; i++) {
		(ans += f[n%2][(1<<k)-1][i]) %= P;
	}
	printf("%d", ans);
}

标签:ac,NOIP2013,int,题解,tail,母串,fail,自动机,联考
From: https://www.cnblogs.com/znpdco/p/18071684

相关文章

  • LeetCode[题解] 2864. 最大二进制奇数
    题目给你一个二进制字符串s,其中至少包含一个'1'。你必须按某种方式重新排列字符串中的位,使得到的二进制数字是可以由该组合生成的最大二进制奇数。以字符串形式,表示并返回可以由给定组合生成的最大二进制奇数。注意返回的结果字符串可以含前导零。示例1:输入:s......
  • 2024.03.13 题解
    CF566A.MatchingNames注意到要求公共前缀,所以先对所有字符串建出Trie树,则公共前缀长度等价于Trie树上两节点最近公共祖先的深度。设\(dfn_u\)表示u点的dfs序,\(dep_u\)表示u的深度,\(lca_{u,v}\)表示\(u\)和\(v\)的最近公共祖先。则对于\(dfn_a<dfn_b<d......
  • 洛谷 P2730 魔板 题解 DFS(广度优先搜索)
    题目背景在成功地发明了魔方之后,鲁比克先生发明了它的二维版本,称作魔板。这是一张有 8 个大小相同的格子的魔板:12348765题目描述我们知道魔板的每一个方格都有一种颜色。这 8 种颜色用前 8 个正整数来表示。可以用颜色的序列来表示一种魔板状态,规定从魔板的左......
  • 每日"两"题 题解
    每日“二”题十年OI一场空,不开longlong见祖宗目录每日“二”题ABA题解:最值问题,一个条件在变,考虑使用二分:我们每次查找一个可切的最大巧克力,二分判断能不能这么切即可。C++代码voidsolve(){intn,k,l=1,r=0,ans;cin>>n>>k;vector<pair<int......
  • AT_abc343_g [ABC343G] Compress Strings 题解
    题目传送门前置知识前缀函数与KMP算法|状压DP解法由于\(\sum\limits_{i=1}^{n}|S_{i}|\)极大且不需要记录路径,所以luoguP2322[HNOI2006]最短母串问题的枚举所有可能的字符串\(T\)进行判断不可做。设\(f_{i,j}\)表示当“字符串包含状态”对应的二进制数为\(......
  • abc134F题解
    abc134F题意:定义长度为\(n\)的排列的怪异值为\(\sum_{i=1}^{n}\midp_i-i\mid\),问长度为\(n\),怪异值为\(k\)的排列数。思路:非常妙的dp题。\(\midp_i-i\mid\)可以看成上下两层数,将上层中的\(i\)和下层中的\(j\)匹配,怪异值增加\(i\),\(j\)中较大值减较小值。整体思路为从小到......
  • ARC173A Neq Number 题解
    ARC173ANeqNumber题目大意正整数\(X\)如果满足以下条件,则称为"Neq数":当\(X\)用十进制符号书写时,没有两个相邻的字符是相同的。例如,\(1\)、\(173\)和\(9090\)是Neq数,而\(22\)和\(6335\)不是。给你一个正整数\(K(1\leqK\leq10^{12})\)。请找出第\(K\)小......
  • P1621 集合题解
    题目Caima给你了所有[a,b]范围内的整数。一开始每个整数都属于各自的集合。每次你需要选择两个属于不同集合的整数,如果这两个整数拥有大于等于p的公共质因数,那么把它们所在的集合合并。重复如上操作,直到没有可以合并的集合为止。现在Caima想知道,最后有多少个集合。输入输出......
  • Emgu.CV.Runtime.Windows nuget 安装失败问题解决方案
    一、错误现象我正在尝试从VisualStudio2015中安装emgu.CV.runtime.windows,并通过右键单击引用并通过NuGet安装的推荐方法进行安装。但是我收到以下错误。无法安装包“Emgu.runtime.windows.msvc.rt.x6419.28.29336”。您正在尝试将此包安装到面向.NETFramework,Versio......
  • ChatGPT提问技巧——问题解答提示
    ChatGPT提问技巧——问题解答提示问题解答提示是一种允许模型生成回答特定问题或任务的文本的技术。要做到这一点,需要向模型提供一个问题或任务作为输入,以及与该问题或任务相关的任何附加信息。一些提示示例及其公式如下:示例1:回答事实性问题任务:回答一个事实性问题说......