题意简述
给出\(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; }
   |