The official editorial mentions a solution using an Aho-Corasick Automaton built over the query strings. We run the initial string through the automaton to locate all occurrence positions of each query. The answer can easily be identified for each query by using a sliding window.
More intuitively, instead of building an Aho-Corasick automaton over the queries, let us build a suffix automaton over the input string. Like before, we will need all occurrence positions.
For a state , let denote the ending position of the first occurrence of any string that corresponds to state .
- When we create a new state , then
- When we clone state to create a state , then
With this method, we can easily initialize without any extra time complexity. Let be the set of positions where a string begins in the string. If state corresponds to , then clearly . To find the remainder of occurrence positions, we can take advantage of the structure of the suffix automaton.
All states where is a suffix is a candidate for . Thus, we simply do a BFS/DFS on the suffix-link tree, or the tree formed by building a tree out of the suffix links and rooted at the initial state, starting from state that we arrive at when we run through the suffix automaton. There is a technicality that more than one state may have the same occurrence position. Namely, this happens only with cloned states; thus, we redefine for all cloned states .
We can preprocess all queries, and solve them all with a single BFS/DFS.
C++
Time Complexity:
#include <bits/stdc++.h>using namespace std;using pii = pair<int, int>;Code Snippet: Suffix Automaton (Click to expand)const int MAXN = 1e5 + 1;string S;
Join the USACO Forum!
Stuck on a problem, or don't understand a module? Join the USACO Forum and get help from other competitive programmers!