20200402 月月查华华的手机
下载pdf,获得更好的阅读体验。
提取码:06ez
问题简述
给出字符串 ,查询 是否为 的子串,询问 次。
查询 是否为 的子串可以用序列自动机完成。
序列自动机
在 JSOI2019SC 听过这个科技,现在又查了几个博客复习了一下。
序列自动机的构建
序列自动机的核心在于 数组(由于其他一些字符串算法,常习惯写为 。
代表位置 后字符 第一次出现的位置。
当从位置 移动到位置 时,显然只有一个字符的 值发生变化。
代码:
void Build(void) { n = strlen(s + 1); for(int i = n; i >= 1; i--) { for(int j = 0; j < 26; j++) fail[i - 1][j] = fail[i][j]; fail[i - 1][s[i] - 'a'] = i; } }
序列自动机的查找
从头向后移动匹配,一旦失配,直接失败。
bool check(void) { int m = strlen(t + 1), pos = 0; for(int i = 1; i <= m; i++) { pos = fail[pos][t[i] - 'a']; if(!pos) return false; } return true; }
题解
不难发现,这个题就是个模板题,粘贴好模板就行了。
Code
#include<bits/stdc++.h> using namespace std; const int maxs = 1000000 + 7; int n, T; char s[maxs], t[maxs]; int fail[maxs][28]; void Build(void) { n = strlen(s + 1); for(int i = n; i >= 1; i--) { for(int j = 0; j < 26; j++) fail[i - 1][j] = fail[i][j]; fail[i - 1][s[i] - 'a'] = i; } } bool check(void) { int m = strlen(t + 1), pos = 0; for(int i = 1; i <= m; i++) { pos = fail[pos][t[i] - 'a']; if(!pos) return false; } return true; } int main(void) { scanf("%s", s + 1); Build(); scanf("%d", &T); while(T--) { scanf("%s", t + 1); if(check()) puts("Yes"); else puts("No"); } return 0; }