diff --git a/algorithms/string/aho_corasick.cpp b/algorithms/string/aho_corasick.cpp index 23f03025ab63913ea70c8028b023b2a56ba11e3c..f5c29f2cf1c916493dabcb4f7a39af079a7f6b30 100644 --- a/algorithms/string/aho_corasick.cpp +++ b/algorithms/string/aho_corasick.cpp @@ -13,11 +13,11 @@ // *: Use only if "match_all" is necessary struct AhoCorasick { struct Node { - //*: vector<int> words; + vector<int> words; map<char,int> next; - int idx, fail, cnt, hei; + int fail, cnt, hei, occ; - Node() : idx(-1), fail(0), cnt(0), hei(0) {} + Node() : fail(0), cnt(0), hei(0), occ(-1) {} int has(char i) { return next.count(i); } int &operator[](char i) { return next[i]; } }; @@ -36,7 +36,7 @@ struct AhoCorasick { for (int i = 0; i < s.size(); n = trie[n][s[i]], ++i) if (!trie[n].has(s[i])) { trie[n][s[i]] = trie.size(); - //*: trie[n].hei = i + 1; + trie[n].hei = i + 1; trie.pb(Node()); } return n; @@ -45,10 +45,8 @@ struct AhoCorasick { void build(const vector<string> &v) { for (int i = 0; i < v.size(); ++i) { int n = insert(v[i]); - trie[n].idx = i; - //*: trie[n].words.pb(i); + trie[n].words.pb(i); } - preprocess(); } inline int suffix(int v, char c) { @@ -62,10 +60,14 @@ struct AhoCorasick { for (int i = 0; i != Q.size(); ++i) { int u = Q[i]; for (auto j : trie[u].next) { - trie[j.se].fail = u ? suffix(trie[u].fail, j.fi) : trie[u].fail; - - //*: trie[j.se].words.insert(trie[j.se].words.end(), - // all(trie[trie[j.se].fail].words)); + int &v = trie[j.se].fail; + if (u) { + v = suffix(trie[u].fail, j.fi); + trie[j.se].occ = trie[v].words.size() ? v : trie[v].occ; + } else { + v = trie[u].fail; + trie[j.se].occ = -1; + } Q.pb(j.se); } } @@ -80,14 +82,13 @@ struct AhoCorasick { u = suffix(u, i); trie[u].cnt++; } - for (int i = top.size() - 1; i >= 0; --i) trie[trie[top[i]].fail].cnt += trie[top[i]].cnt; vector<int> ans; - for (auto i : trie) - if (i.idx != -1 && i.cnt) - ans.pb(i.idx); + for (auto &i : trie) + if (i.cnt && i.words.size()) + for (auto j : i.words) ans.pb(j); sort(all(ans)); return ans; @@ -103,7 +104,15 @@ struct AhoCorasick { u = suffix(u, p[i]); for (auto j : trie[u].words) ans.pb({j, i - trie[u].hei + 1}); + + int x = u; + while (trie[x].occ != -1) { + x = trie[x].occ; + for (auto j : trie[x].words) + ans.pb({j, i - trie[x].hei + 1}); + } } + sort(all(ans)); return ans; } }; diff --git a/contests/Cadernaveis/URI1141.cpp b/contests/Cadernaveis/URI1141.cpp index 36bf967bdb17e9a9fb6473d4a81f3f7fe5d357df..395917ee6f96616cc027d0a07cc8628f669f9af0 100644 --- a/contests/Cadernaveis/URI1141.cpp +++ b/contests/Cadernaveis/URI1141.cpp @@ -23,11 +23,11 @@ using ii = pair<int,int>; struct AhoCorasick { struct Node { - int fail; + int fail, occ; vector<int> words; map<char,int> next; - Node() : fail(0) {} + Node() : fail(0), occ(-1) {} int has(char i) { return next.count(i); } int &operator[](char i) { return next[i]; } }; @@ -68,8 +68,14 @@ struct AhoCorasick { for (int i = 0; i != Q.size(); ++i) { int u = Q[i]; for (auto j : trie[u].next) { - trie[j.se].fail = u ? suffix(trie[u].fail, j.fi) : trie[u].fail; - trie[j.se].words.insert(trie[j.se].words.end(), all(trie[trie[j.se].fail].words)); + int &v = trie[j.se].fail; + if (u) { + v = suffix(trie[u].fail, j.fi); + trie[j.se].occ = trie[v].words.size() ? v : trie[v].occ; + } else { + v = trie[u].fail; + trie[j.se].occ = -1; + } Q.pb(j.se); } } @@ -80,22 +86,6 @@ int n; int dp[10101]; vector<string> v; -int solve(int i, AhoCorasick &aho) { - if (i == n) return 0; - if (dp[i] != -1) return dp[i]; - - int u = 0; - int grt = 0; - for (auto j : v[i]) { - u = aho.suffix(u, j); - for (auto k : aho.trie[u].words) - if (v[k].size() < v[i].size()) - grt = max(grt, solve(k, aho) + 1); - } - - return dp[i] = grt; -} - int main() { ios::sync_with_stdio(0); cin.tie(0); @@ -103,14 +93,34 @@ int main() { while (cin >> n && n) { v.clear(); v.resize(n); - for (auto &i : v) cin >> i; + for (auto &i : v) + cin >> i; + + sort(all(v), [](const string &a, const string &b) { + return a.size() > b.size(); + }); + AhoCorasick aho(v); + for (int i = n - 1; i >= 0; --i) { + int grt = 0, u = 0; + for (auto j : v[i]) { + u = aho.suffix(u, j); + for (auto k : aho.trie[u].words) + if (k != i) + grt = max(grt, dp[k] + 1); + + int x = u; + while (aho.trie[x].occ != -1) { + x = aho.trie[x].occ; + for (auto k : aho.trie[x].words) + if (k != i) + grt = max(grt, dp[k] + 1); + } + } + dp[i] = grt; + } - mset(dp, -1); - int ans = 0; - for (int i = 0; i < n; ++i) - ans = max(ans, solve(i, aho) + 1); - cout << ans << ende; + cout << (*max_element(dp, dp + n) + 1) << ende; } return 0; diff --git a/contests/Cadernaveis/UVA10679_aho.cpp b/contests/Cadernaveis/UVA10679_aho.cpp index e5e69c52bf64a1e737ae2f6d5c350d86e1e0f841..15760390a8aeff86d0c11dbd1efbef3da4e26c8f 100644 --- a/contests/Cadernaveis/UVA10679_aho.cpp +++ b/contests/Cadernaveis/UVA10679_aho.cpp @@ -1,3 +1,5 @@ +/// I Love Strings! (Aho-Corasick) + #include <bits/stdc++.h> #define MAX 1010101 @@ -22,10 +24,11 @@ using ii = pair<int,int>; struct AhoCorasick { struct Node { + int fail, occ, cnt; + vector<int> words; map<char,int> next; - int idx, fail, cnt, hei; - Node() : idx(-1), fail(0), cnt(0), hei(0) {} + Node() : fail(0), occ(-1), cnt(0) {} int has(char i) { return next.count(i); } int &operator[](char i) { return next[i]; } }; @@ -52,9 +55,8 @@ struct AhoCorasick { void build(const vector<string> &v) { for (int i = 0; i < v.size(); ++i) { int n = insert(v[i]); - trie[n].idx = i; + trie[n].words.pb(i); } - preprocess(); } inline int suffix(int v, char c) { @@ -68,7 +70,14 @@ struct AhoCorasick { for (int i = 0; i != Q.size(); ++i) { int u = Q[i]; for (auto j : trie[u].next) { - trie[j.se].fail = u ? suffix(trie[u].fail, j.fi) : trie[u].fail; + int &v = trie[j.se].fail; + if (u) { + v = suffix(trie[u].fail, j.fi); + trie[j.se].occ = trie[v].words.size() ? v : trie[v].occ; + } else { + v = trie[u].fail; + trie[j.se].occ = -1; + } Q.pb(j.se); } } @@ -77,7 +86,8 @@ struct AhoCorasick { vector<int> match(const string &p) { int u = 0; - for (auto i : p) { + vector<int> ans; + for (auto &i : p) { u = suffix(u, i); trie[u].cnt++; } @@ -85,12 +95,12 @@ struct AhoCorasick { for (int i = top.size() - 1; i >= 0; --i) trie[trie[top[i]].fail].cnt += trie[top[i]].cnt; - vector<int> ans; for (auto i : trie) - if (i.idx != -1 && i.cnt) - ans.pb(i.idx); + if (i.cnt && i.words.size()) + for (auto j : i.words) ans.pb(j); sort(all(ans)); + ans.erase(unique(all(ans)), ans.end()); return ans; } }; @@ -109,16 +119,12 @@ int main() { AhoCorasick aho(v); vector<int> ans = aho.match(s); - map<string,int> M; for (int i = 0, j = 0; i < n; ++i) { if (j < ans.size() && ans[j] == i) { - M[v[j]] = 1; ++j; + cout << 'y' << ende; ++j; } else - if (!M[v[j]]) M[v[j]] = 0; + cout << 'n' << ende; } - - for (int i = 0; i < n; ++i) - cout << (M[v[i]] ? 'y' : 'n') << ende; } return 0;