SPOJ Longest Common Substring II 字尾自動機(列印)
給無數個串,問你他們合起來的公共子串最長是多少。
比人說WA10就不理解字尾自動機,我覺得我不理解字尾自動機居然AC了……
1、用第一個串做出字尾自動機
2、之後每一個串,都可以在自動機上跑。
3、一個串,在自動機上跑,可以知道 "走到這個狀態,走了幾步。同時!!這個步數要取max!" 一個狀態如果能到達,那麼這個狀態的父狀態一定可達(並且一定存在步數為父狀態的len的方案)。
4、所以我們跑完自動機後,利用反拓撲序DP的方法,可以得到所有前序狀態的步數(就等於len值)。
5、我們就知道,一個串在自動機上到所有狀態的最大步數。 把N個串都跑一次,取min,輸出即可。
(比賽要列印這份程式碼帶著!)
#include <iostream> #include <cstring> #include <cstdlib> #include <cstdio> using namespace std; const int CHAR = 26; const int MAXN = 250000 * 2 + 100; char str[MAXN]; bool duanyan(bool flag) { if (!flag) { throw 0; } } struct SAM_Node { SAM_Node *fa, *next[CHAR]; int len; int id, pos; int dp, ans; SAM_Node(){} SAM_Node(int _len) { fa = 0; len = _len; dp=0; ans = 1000000000; memset(next, 0, sizeof(next)); } }; SAM_Node SAM_node[MAXN *2], *SAM_root, *SAM_last; int SAM_size; SAM_Node * newSAM_Node(int len) { SAM_node[SAM_size] = SAM_Node(len); SAM_node[SAM_size].id = SAM_size; SAM_node[SAM_size].dp = 0; return &SAM_node[SAM_size++]; } SAM_Node *newSAM_Node(SAM_Node *p) { SAM_node[SAM_size] = *p; SAM_node[SAM_size].id = SAM_size; SAM_node[SAM_size].dp = 0; return &SAM_node[SAM_size++]; } void SAM_init() { SAM_size = 0; SAM_root = SAM_last = newSAM_Node(0); SAM_node[0].pos = 0; } void SAM_add(int x, int len) { SAM_Node *p = SAM_last, *np = newSAM_Node(p -> len+1); np -> pos = len; SAM_last = np; for (;p && !p -> next[x]; p = p -> fa) p -> next[x] = np; if (!p) { np -> fa = SAM_root; return; } SAM_Node *q = p -> next[x]; if (q -> len == p-> len+1) { np -> fa = q; return; } SAM_Node *nq = newSAM_Node(q); nq -> len = p -> len + 1; q -> fa = nq; np -> fa = nq; for (;p && p-> next[x] == q; p = p -> fa) p -> next[x] = nq; } int topcnt[MAXN]; SAM_Node *topsam[MAXN*2]; void SAM_build(char *s) { SAM_init(); int len = strlen(s); for (int i = 0 ;i < len; ++ i) SAM_add(s[i] - 'a' , i + 1); } int g[MAXN], f[MAXN]; void SAM_search() { SAM_Node *now = SAM_root; int len = strlen(str); int ans = 0; for (int i = 0; i < SAM_size; ++ i) { SAM_node[i].dp = 0; } for (int i = 0; i < len; ++ i) { int t = str[i] - 'a'; if (now -> next[t]) { now =now -> next[t]; ++ans; } else { while (now != SAM_root && !now -> next[t]) now = now -> fa; if (now -> next[t]) { ans = now -> len + 1; now = now -> next[t]; } else { now = SAM_root; ans = 0; } } now -> dp = max(ans, now->dp); } for (int i = SAM_size - 1; i > 0; -- i) { SAM_Node *now = topsam[i]; if (now -> dp) now -> fa -> dp = max(now -> fa -> dp, now -> fa -> len); } for (int i = 0; i < SAM_size; ++ i) { SAM_node[i].ans = min(SAM_node[i].ans, SAM_node[i].dp); } } void pg() { for (int i = 0; i < SAM_size; ++ i) { cout <<"@"<< SAM_node[i].id<< endl; for (int j = 0; j < 26; ++ j) { if (SAM_node[i].next[j]) { cout << SAM_node[i].next[j] -> id << endl; } } if (i) cout << "fa: " << SAM_node[i].fa -> id << endl; cout<<"===="<<endl; } } int main() { int t; scanf("%s", str); SAM_build(str); int n = strlen(str); memset(topcnt, 0, sizeof(topcnt)); memset(f, 0, sizeof(f)); memset(r, 0, sizeof(r)); for (int i = 0; i < SAM_size; ++ i) topcnt[SAM_node[i].len] ++ ; for (int i = 1; i <= n; ++ i) topcnt[i] += topcnt[i - 1]; for (int i = 0; i < SAM_size ; ++ i) topsam[-- topcnt[SAM_node[i].len]] = &SAM_node[i]; for (int i = 0; i < SAM_size; ++ i) SAM_node[i].dp = SAM_node[i].len; int cnt=0; //pg(); while (~scanf("%s", str)) { SAM_search(); } int ans = 0; for (int i = 1; i < SAM_size; ++ i) { ans = max(SAM_node[i].ans, ans); } cout << ans << endl; return 0; }
相關推薦
SPOJ Longest Common Substring II 字尾自動機(列印)
給無數個串,問你他們合起來的公共子串最長是多少。 比人說WA10就不理解字尾自動機,我覺得我不理解字尾自動機居然AC了…… 1、用第一個串做出字尾自動機 2、之後每一個串,都可以在自動機上跑。 3、一個串,在自動機上跑,可以知道 "走到這個狀態,走了幾步。同時!!這
SPOJ 1812 Longest Common Substring II 字尾自動機求多字串最長公共子串
題意: 給若干字串,求它們的最長公共子串的長度。 題解:字尾自動機。 對第一個串建立SAM,並拓撲排序。 用後面的串分別匹配。 對於SAM,每個節點新增兩個值ml,ans; ml代表該節點滿足單一字串時的最大值,匹配完一個字串後重置為0; an
Longest Common Substring II-字尾自動機
LCS2 - Longest Common Substring II Description A string is finite sequence of characters over a non-empty finite set Σ. In thi
Longest Common Substring II [字尾自動機]
注意更新祖先的狀態 #include <iostream> #include <cstdio> #include <cstring> #include <cstdlib> #define cl(a) memset(
SPOJ1812 Longest Common Substring II 字尾自動機
題目描述: 求n(n<=10)個字串的最長公共子串的長度,每個字串長度小於等於105 思路: 對於第一個串建字尾自動機,然後別的串在上面匹配, 匹配的過程和SPOJ1811差不多,但是要記下經過的每一個節點的當前匹配的最長長度。 然後,按照
2018.12.15【SPOJ-LCS2】Longest Common Substring II(字尾自動機SAM)
傳送門 解析: 這道題可以把所有串接在一起構建字尾自動機來做,但是那樣還不如寫字尾陣列。。。 所以這裡提供一個只有字尾自動機能實現的做法。 思路: 首先構建出第一個串的字尾自動機。 然後拿其他的串放到字尾自動機上面跑。同時更新答案。 程式碼裡面的
【SPOJ】Longest Common Substring II (後綴自動機)
公共子串 排序 -i max node bstr cst 後綴 post 【SPOJ】Longest Common Substring II (後綴自動機) 題面 Vjudge 題意:求若幹個串的最長公共子串 題解 對於某一個串構建\(SAM\) 每個串依次進行匹配 同時記
Longest Common Substring II(字尾自動機求多個串的最長公共子串)
A string is finite sequence of characters over a non-empty finite set Σ. In this problem, Σ is the set of lowercase letters. Substring, also called factor
Longest Common Substring II (字尾自動機)
A string is finite sequence of characters over a non-empty finite set Σ. In this problem, Σ is the set of lowercase letters. Substring, also called factor
Longest Common Substring II(字尾自動機)
題目描述 傳送門 題意:給出若干串,求最長公共子串。 題解 這明明就是一道sa的題嘛,可是為了練習sam用sam來寫 首先對於第一個串構建sam 對於每一個狀態s,記錄一下它對於每一個串
SPOJ LCS2 - Longest Common Substring II 後綴自動機 多個串的LCS
plus namespace sub align call 節點 inline cto res LCS2 - Longest Common Substring II no tags A string is finite sequence of cha
SPOJ 1812 LCS2 - Longest Common Substring II (後綴自動機)【兩種做法】
spoj name memset cstring pre fin cbi dcb 每次 手動博客搬家: 本文發表於20181217 23:54:35, 原地址https://blog.csdn.net/suncongbo/article/details/85058680 人
[SPOJ] (1812) Longest Common Substring II ---- SAM(多個串的最長公共子串)
題目傳送門 做法: 類似求兩個串的最長公共子串。 我們對第一個串建立自動機,然後把剩餘的n-1個串放進自動機上匹配。 每個串都儲存它們在每個狀態上的匹配的最大長度ml, 然後對於每個狀態,維護一個數組
【再談字尾自動機(入門)】[SPOJLCS2]Longest Common Substring II
題目大意 給出n個字串n<=10,每個字串長度小於100000,求它們的最長公共串的長度。 分析 關於字尾自動機 複習過程中再看字尾自動機,把許多初學的時候沒弄懂的問題解決了。 首先
Spoj LCS2 - Longest Common Substring II
ast aaa long long algorithm else stream 輸入輸出格式 init ++ 題目描述 A string is finite sequence of characters over a non-empty finite set Σ. In t
【SPOJ - LCS2】Longest Common Substring II【SAM】
題意 求出多個串的最長公共子串。 分析 剛學SAM想做這個題的話最好先去做一下那道codevs3160。求兩個串的LCS應該怎麼求?把一個串s1建自動機,然後跑另一個串s2,然後找出s2每個字首的最長公共字尾。那麼多個的時候,我們也用這種類似的方法,但是我們求最長
spoj LCS2 - Longest Common Substring II && LCS - Longest Common Substring
const ima space poj 集合 scanf cst printf common 多串LCS很適合SA但是我要學SAM 對第一個串求SAM,然後把剩下的串在SAM上跑,也就是維護p和len,到一個點,如果有ch[p][c],就p=ch[p][c],len++,否
【SPOJ】Longest Common Substring II
【SPOJ】Longest Common Substring II 多個字串求最長公共子串 還是將一個子串建SAM,其他字串全部跑一邊,記錄每個點的最大貢獻 由於是所有串,要對每個點每個字串跑完後去最小值才是每個點的最終貢獻 #include<iostream> #include<cst
spoj1812 LCS2 - Longest Common Substring II
sent rsize least urn min you doesn 排序 sort 地址:http://www.spoj.com/problems/LCS2/ 題面: LCS2 - Longest Common Substring II no tags
SP1812 LCS2 - Longest Common Substring II
\(\color{#0066ff}{ 題目描述 }\) 題面描述 給定一些字串,求出它們的最長公共子串 輸入格式 輸入至多\(10\) 行,每行包含不超過\(100000\) 個的小寫字母,表示一個字串 輸出格式 一個數,最長公共子串的長度 若不存在最長公共子串,請輸出\(0\) 。 \(\color{#