题意简述
给出\(n\)个单词,统计每个单词在全体单词(包括自身)中的出现次数
题目分析
对多个模式串进行匹配,求每个模式串的出现次数,显然是AC自动机模版题
本题与模版的区别在于,本题中单词可能会有重复,因此要用一个\(cnt\)数组记录\(Trie\)树上每个节点被覆盖了几次,再用一个\(vis\)数组记录当前节点是否已经被累加过了
如果当前节点\(i\)还没有被累加过(\(vis_i = false\)),就将它往上能跳到的节点都加上\(cnt_i\),扫完后再将\(vis_i\)变为\(true\)
代码
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76
| #include<bits/stdc++.h> using namespace std;
const int MAXN = 1000000 + 5; const int MAXM = 200 + 5;
string s[MAXM]; bool vis[MAXN]; int t[MAXN][26], sum[MAXN], cnt[MAXN], ed[MAXN], ans[MAXN]; int fail[MAXN]; int tot;
int insert(string& s) { int p = 0; for(int i = 0; i < s.length(); i++) { if(t[p][s[i] - 'a'] == 0) { t[p][s[i] - 'a'] = ++tot; } p = t[p][s[i] - 'a']; cnt[p]++; } return p; }
void getFail() { queue<int> q; for(int i = 0; i < 26; i++) { if(t[0][i]) { q.push(t[0][i]); } } while(!q.empty()) { int u = q.front(); q.pop();
for(int i = 0; i < 26; i++) { if(t[u][i]) { fail[t[u][i]] = t[fail[u]][i]; q.push(t[u][i]); } else { t[u][i] = t[fail[u]][i]; } } } }
void query(string& s) { int p = 0;
for(int i = 0; i < s.length(); i++) { p = t[p][s[i] - 'a'];
for(int j = p; j != 0 && !vis[p]; j = fail[j]) { ans[j] += cnt[p]; } vis[p] = 1; } }
int main() { int n;
cin >> n; for(int i = 1; i <= n; i++) { cin >> s[i]; ed[i] = insert(s[i]); } getFail(); for(int i = 1; i <= n; i++) { query(s[i]); } for(int i = 1; i <= n; i++) { cout << ans[ed[i]] << endl; }
return 0; }
|