乙個模式串s(|s|<=1e5),
n(n<=1e5)個詢問,每次詢問乙個串t(|t|<=1e3)
每次詢問t是不是s的子串行
建一下序列自動機,然後每次在自動機上跑一下,
類似trie樹,看看是否存在即可
預處理自動機o(26*|s|),匹配o(n*t)
算是學習了一下序列自動機
建子串行自動機的時候,優先出現的字母先構建
比如aaabab的ab串,就是由第乙個a和第四個b建的
這樣保證了不會錯過後續來的字串
此外,每次加入乙個新字元時,考慮能給哪些子串行帶來貢獻
那麼就是在以往所有的子串行後增加乙個新字元即可,
只需列舉過往所有子串行的最後乙個字元是什麼,
而由於序列自動機的優先性,
任意乙個子串行的最後乙個字元x,肯定是最後乙個被加入的字元x,
所以從『a』到『z'列舉,補到最後乙個字元位置後面即可,
注意到這裡許多子串行的兒子節點都是共用的乙個節點,
所以這也使得若干子串行都是共用的,
補在這個節點後面就相當於補在所有以這個子節點為結尾節點的子串行後面
複雜度據說是o(n*a),但我覺得好像是o(所有本質不同子串行的長度之和)
#include#include#includeusing namespace std;
const int maxn=1e5+10;
int n,len,rt;
char s[maxn],t[maxn];
int par[maxn];
int head[26],last[26];
int ch[maxn][26];
void add(int x)
bool find(char s)
{ int rt,len=strlen(s);
for(int i=0;i不妨設字串只由小寫字母構成,
next[i][j]表示下標從i起第一次出現字母j的位置
預處理的時候倒著dp,next[i][s[i]-'a']=i,否則next[i][j]=next[i+1][j]
初始時,賦狀態next[i][j]=n+1或inf
子串行匹配時,每次貪心地找到第乙個字元進行匹配
預處理複雜度o(n*a),匹配複雜度o(|s|)
由於**比較簡單就不寫了
AC自動機板子
include p3808 define m 1000007 using namespace std int trie m 26 cnt,val m last m fail m n char s m void build val u 給每個模式串結尾打上標記 void getfail int r t...
序列自動機
昨天在牛客碰到了這樣的一道題,判斷一些字串是不是原串的子串行,因為之前做過一些lcs子串行的題,就想,這不賊簡單,用lcs求一下每個子串和原串,然後判斷lcs的長度是不是等於要判斷的那個串的長度,然後,t了,因為dp求lcs幾個串還好說,但是當串又多又長時,不僅會t,dp陣列不弄滾動陣列還會mle,...
字尾自動機 序列自動機綜合
好像序列自動機還沒有寫過 串長為n的串共有n 1個節點,除了串中的n個節點,還有乙個空的根節點放在串首。每個節點至多有26條出邊,每條邊連向它之後的第乙個字元。串中的任意乙個子串行對應了一條根到某個節點的路徑。且每條路徑對應乙個不同的子串行。每個節點的parent是這個字母上一次出現的位置。更新只要...