TJOI2013 words (AC automata)

Topic

Insert picture description here

answer

  1. In the application of AC automata, the core of AC automata is the ne array, which means that all suffixes of words ending with a node can match the longest prefix in the dictionary tree, and the pointer points to the end of the prefix.
  1. What I asked for in the question is the number of times the word appears in all other words (including myself). As shown in the figure, Insert picture description here
    we can transform the question:Find all prefixes that meet the requirements (the suffix is ​​equal to the required words)
  1. So now there are two problems: how to count all the prefixes, and how to change them when the conditions are met. The process we are building Trie is actuallyEvery time you insert a new word, then every time you insert from the root node down, and each time you pass through a node, then the prefix ending with this node should be +1, In this way, the prefix corresponding to each node is counted.
  1. Recall the function of ne again: what it can find is the longest prefix that can be matched for the suffix of each word. What we require is for each prefix, which prefixes its suffix can match, and compare , Ne asks for the longest one, what we want is all that can be matched, so what to do, recall KMP
  1. For ne [i] = j in KMP, it is the longest length that can be matched from 1 at the end of i in the range of 1-i, so how to find all the prefixes and suffixes in 1-i to overlap, it is actually an iteration In the process of, first ne[i] is one, then ne[ ne[i]] is also, ne [ne[ ne[i]]] …all the way to the beginning, it is the part where the prefix and the prefix overlap
  1. The same is true for AC automata, we only need to update from back to front in topological order, accumulate the results of each update, so that the value corresponding to each node is the answer, find the node number corresponding to the end of each word, and output The prefix is ​​the answer

Code

#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>

using namespace std;
const int N = 1e6 + 10;

int n;
char s[N];
int tr[N][26], f[N], idx;
int ne[N], q[N];
int id[210];

void insert(int x) {
    
    
    int p = 0;
    for (int i = 0; s[i]; i++) {
    
    
        int u = s[i] - 'a';
        if (!tr[p][u]) tr[p][u] = ++idx;
        p = tr[p][u];
        f[p]++;
    }
    id[x] = p;
}

void build() {
    
    

    int hh = 0, tt = -1;
    for (int i = 0; i < 26; i++) {
    
    
        if (tr[0][i]) q[++tt] = tr[0][i];
    }

    while (hh <= tt) {
    
    
        int t = q[hh++];
        for (int i = 0; i < 26; i++) {
    
    
            int p = tr[t][i];
            if (!p) tr[t][i] = tr[ne[t]][i];
            else {
    
    
                ne[p] = tr[ne[t]][i];
                q[++tt] = p;
            }
        }
    }
}

int main() {
    
    

    cin >> n;
    for (int i = 1; i <= n; i++) {
    
    
        cin >> s;
        insert(i);
    }

    build();

    for (int i = idx - 1; i >= 0; i--) {
    
    
        f[ne[q[i]]] += f[q[i]];
    }

    for (int i = 1; i <= n; i++) {
    
    
        cout << f[id[i]] << endl;
    }

    return 0;
}

Guess you like

Origin blog.csdn.net/qq_44791484/article/details/113800316