昨天在牛客碰到了這樣的一道題,判斷一些字串是不是原串的子串行,,,因為之前做過一些lcs子串行的題,,,就想,這不賊簡單,,用lcs求一下每個子串和原串,,然後判斷lcs的長度是不是等於要判斷的那個串的長度,,,然後,,t了,,,
因為dp求lcs幾個串還好說,,但是當串又多又長時,,,不僅會t,,dp陣列不弄滾動陣列還會mle,,,
之後看了題解了解到這個處理子串行的好東西,序列自動機,,,
序列自動機實質還是用空間換時間,,它有乙個陣列 nxt[i][j](nxt[maxn][26]nxt[i][j](nxt[maxn][26],,表示原串s的第i位後面那26個字元j出現的最早的位置,,
相當於建了一棵樹,,根節點是乙個空節點,,,它有26個孩子,,表示每乙個字母最早出現的位置,,,那麼原串的第乙個字元 s[0]s[0] 就使得 nxt[0][s[0]−′a′]=1nxt[0][s[0]−′a′]=1,,第二個字元就是 nxt[0][s[1]−′a′]=2nxt[0][s[1]−′a′]=2,,,等等等等,,,同樣第乙個字元也有這樣的26個孩子,,,這樣從根節點到任意乙個葉子節點都是原串的乙個子串行,,
這樣判斷乙個字串t是不是原串的子串行只要將t中的每乙個字元在那棵樹里跑一下,,,如果存在這樣的路徑就表示t是s的乙個子串行,,,
那麼怎麼建樹呢,,
如果正著建樹的話每次都要找到後面最早出現的字元的位置,,,不太好弄,,所以我們倒著建樹,,用乙個 now[26]now[26] 陣列表示遍歷到第i個字元時後面這26個字元從後往前看最晚出現的位置,,也就是第i個字元後面的26個字元最在出現的位置,,,用它來更新 nxt[i][1→26]nxt[i][1→26],,然後再將這個字元在 nownow 陣列中的位置更新為當前的位置,,now[s[i]−′a′]=inow[s[i]−′a′]=i,,,
最後的實現就是這樣子:
int nxt[maxn][30];
int now[30];
char s[maxn];
void init()
}
例題:
月月和華華一起去吃飯了。期間華華有事出去了一會兒,沒有帶手機。月月出於人類最單純的好奇心,開啟了華華的手機。哇,她看到了一片的qq推薦好友,似乎華華還沒有瀏覽過。月月頓時醋意大發,出於對好朋友的關心,為了避免華華浪費太多時間和其他網友聊天,她要刪掉一些推薦好友。但是為了不讓華華發現,產生猜疑,破壞了他們的友情,月月決定只刪華華有可能搭訕的推薦好友。
月月熟知華華搭訕的規則。華華想與某個小姐姐搭訕,當且僅當小姐姐的暱稱是他的暱稱的子串行。為了方便,華華和小姐姐的暱稱只由小寫字母構成。為了更加方便,保證小姐姐的暱稱長度不會比華華的長。
現在月月要快速的判斷出哪些推薦好友要刪掉,因為華華快回來了,時間緊迫,月月有點手忙腳亂,所以你趕緊寫個程式幫幫她吧!
第一行輸入乙個字串a表示華華的暱稱。
第二行輸入乙個正整數n表示華華的推薦好友的個數。
接下來n行,每行輸入乙個字串bibi表示某個推薦好友的暱稱。
輸出n行,對於第i個推薦好友,如果華華可能向她搭訕,輸出yes,否則輸出no。
注意大寫,同時也要注意輸出效率對演算法效率的影響。
**:
#includeusing namespace std;
int nxt[1000006][27],now[27],n;
string s,t;
int main()//序列自動機初始化
cin>>n;
while(n--)
else
}if(flag)printf("yes\n");
else printf("no\n");}}
return 0;
}
字尾自動機 序列自動機綜合
好像序列自動機還沒有寫過 串長為n的串共有n 1個節點,除了串中的n個節點,還有乙個空的根節點放在串首。每個節點至多有26條出邊,每條邊連向它之後的第乙個字元。串中的任意乙個子串行對應了一條根到某個節點的路徑。且每條路徑對應乙個不同的子串行。每個節點的parent是這個字母上一次出現的位置。更新只要...
子串行自動機
貼一題 題意 輸入乙個人字串a,再輸入乙個字串b,問b是否是a的子串行,是則輸出yes,否則輸出no。思路 暴力肯定是會超時的,既然時間會超,那麼只能用空間換時間,採用乙個比較冷門的演算法 子串行自動機。子串行自動機適合於字串中的字元種類數偏少,且已知。思路很簡單,假設 主序列 為 abcade 建...
序列自動機 模板
南昌邀請賽網路賽m題 subsequence 題意 給你乙個字串s,長度小於1e5,然後n次詢問,n小於1e5,每次輸入乙個字串t,問t是不是s的子串行。t長度小於1000 input abcdefg 3abc adgcba output yes yesno 思路 序列自動機其實就是先預處理出來乙個...