日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

算法学习:后缀自动机

發布時間:2025/7/14 编程问答 19 豆豆
生活随笔 收集整理的這篇文章主要介紹了 算法学习:后缀自动机 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

【前置知識】

AC自動機(沒有什么關聯,但是看懂了會對后綴自動機有不同的理解)

?

【解決問題】

各種子串的問題

?

?

【算法學習】

學習后綴自動機的過程中,看到了許多相關性質和證明,但是奈何才疏學淺(lan)

暫時先放著,到有空再更

?

【算法分析】

后綴自動機和AC自動機和回文自動機的不同點在于

后綴自動機是個DAG,而AC自動機和回文自動機是

?

?

首先理解? ?endpos 數組,每個子串都有一個endpos數組,表示他在字符串中出現的位置的結束位置

而endpos數組相同的子串,就被稱為endpos類

而顯然易見的,endpos類中最長的子串,能夠在子類中找到他的所有子串

而后綴自動機中的節點,就是endpos類,所代表的字符串,也可以表示為這個endpos類中最長的子串

?

節點之間的邊,是互相之間的字母

通過字母走到節點,能夠得到關于這個節點子串的后綴

即此節點所代表的整個 endpos 類

?

right [ x ] /zhi [ x ] 數組代表的是,這個節點所代表的子串出現過的次數

maxlen [ x ] / len 數組表示的是,這個節點所代表的endpos類中出現的最長子串長度

?

?

#include<cstdio> #include<cstring> #include<queue> #include<algorithm> #define ll long long using namespace std; const int MAXN = 2*1e6 + 10; const int CHAR = 27; struct note {int ch[CHAR];int fa;ll len; }dian[MAXN]; int zhi[MAXN]; int cnt=1, now=1; char s[MAXN]; void insert(int c) {int p = now, np = now = ++cnt; zhi[cnt] = 1;dian[np].len = dian[p].len + 1;for (;p && !dian[p].ch[c]; p = dian[p].fa) dian[p].ch[c] = np;if (!p) dian[np].fa = 1;else{int q = dian[p].ch[c];if (dian[q].len == dian[p].len + 1) dian[np].fa = q;else{int nq = ++cnt;dian[nq] = dian[q];dian[nq].len = dian[p].len + 1;dian[q].fa = dian[np].fa = nq;for (; p && dian[p].ch[c] == q; p = dian[p].fa)dian[p].ch[c] = nq;}} } ll ans = 0; int cd; int st[MAXN],top; struct NOTE {int to;int nt; }edge[MAXN]; void add(int x, int y) {top++; edge[top].nt = st[x]; edge[top].to = y; st[x] = top; } void dfs(int x) {for (int i = st[x]; i != -1; i = edge[i].nt){dfs(edge[i].to);zhi[x] += zhi[edge[i].to];}if (zhi[x] != 1) ans = max(ans, zhi[x] * dian[x].len); } int main() {memset(st, -1, sizeof(st));scanf("%s", s); cd = strlen(s);//printf("**\n");for (int i = 0; i < cd; i++) insert(s[i] - 'a'+1);//printf("**\n");for (int i = 2; i <= cnt; i++)add(dian[i].fa, i);//printf("**\n");dfs(1);printf("%lld\n", ans);return 0; }

?

?

?


【模板題】

【HDU 6194】

求字符串中出現 k 次的子串個數

【思路分析】

right [ x ] 數組中保存的就是這個 endpos類 所包含的所有子串出現的次數,而當這個次數等于 k 時,就說明有出現 k 次的子串

之所以需要用 maxlen [ x ] 減去 maxlen [ fa [ x ] ] 是因為。。。。。好吧,我還不是很熟 fa [ x ] 所代表的含義

?

1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 #include<algorithm> 5 #define ll long long 6 using namespace std; 7 const int MAXN = 200000+ 10; 8 const int CHAR = 27; 9 struct note 10 { 11 int ch[CHAR]; 12 int fa; 13 int len; 14 }dian[MAXN]; 15 int zhi[MAXN]; 16 int cnt = 1, now = 1; 17 char s[MAXN]; 18 void insert(int c) 19 { 20 int p = now, np = now = ++cnt; 21 zhi[cnt] = 1; 22 dian[np].len = dian[p].len + 1; 23 for (; p && !dian[p].ch[c]; p = dian[p].fa) 24 dian[p].ch[c] = np; 25 if (!p) dian[np].fa = 1; 26 else 27 { 28 int q = dian[p].ch[c]; 29 if (dian[q].len == dian[p].len + 1) dian[np].fa = q; 30 else 31 { 32 int nq = ++cnt; 33 zhi[cnt] = 0; 34 dian[nq] = dian[q]; 35 dian[nq].len = dian[p].len + 1; 36 dian[q].fa = dian[np].fa = nq; 37 for (; p && dian[p].ch[c] == q; p = dian[p].fa) 38 dian[p].ch[c] = nq; 39 } 40 } 41 } 42 int cd; 43 void build() 44 { 45 static int c[MAXN] = { 0 }; 46 static int ss[MAXN] = { 0 }; 47 memset(c, 0, sizeof(c)); 48 for (int i = 1; i <= cnt; i++) 49 { 50 c[dian[i].len]++; 51 } 52 for (int i = 1; i <= cd; i++) 53 c[i] += c[i - 1]; 54 for (int i = 1; i<=cnt; i++) 55 { 56 ss[c[dian[i].len]--] = i; 57 } 58 for (int i =cnt; i>=2; i--) 59 { 60 zhi[dian[ss[i]].fa] += zhi[ss[i]]; 61 } 62 return; 63 } 64 void init() 65 { 66 for (int i = 0; i <= cnt; i++) 67 { 68 for (int j = 0; j < CHAR; j++) 69 dian[i].ch[j] = 0; 70 dian[i].fa = 0; 71 dian[i].len = 0; 72 zhi[i] = 0; 73 }cnt = now = 1; 74 return; 75 } 76 int main() 77 { 78 int T; 79 scanf("%d", &T); 80 while(T--) 81 { 82 int k; 83 scanf("%d", &k); 84 scanf("%s", s); cd = strlen(s); 85 for (int i = 0; i < cd; i++) insert(s[i] - 'a' + 1); 86 build(); 87 ll ans = 0; 88 //printf("***\n"); 89 // for (int i = 1; i <= cnt; i++) 90 // printf("%d\n", zhi[i]); 91 //printf("***\n"); 92 for (int i = 2; i <= cnt; i++) 93 if (zhi[i] == k) 94 ans += dian[i].len - dian[dian[i].fa].len; 95 printf("%lld\n", ans); 96 init(); 97 } 98 return 0; 99 }

?

轉載于:https://www.cnblogs.com/rentu/p/11508652.html

總結

以上是生活随笔為你收集整理的算法学习:后缀自动机的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。