[kuangbin] suffix automata problem solution

[kuangbin] suffix automata problem solution

After learning the suffix automaton, I recommend several good learning materials:

  1. Mr. clj's NOI on-site lecture PPT is very detailed but not very easy to understand
  2. Menci's blog , explaining more mathematics (this is a good thing.jpg), and there are also good pictures for easy understanding
  3. The translation of the classic Russian tutorial , the explanation is very easy to understand, but reading it is a bit like foreign textbooks with a lot of nonsense...

SPOJ - LCS

meaning of the title

The longest common substring, the length of the string is $ \le 250000$, the character set is lowercase letters, the time limit is 294 ms

Problem solving ideas

If you use a suffix array, you can use illegal characters to connect AB to build SA, and find the maximum value of LCP. The complexity is \(O(N)\) (DC3)

I'm not sure if I can pass it, because DC3 is not very good to write, so I won't try it, anyway, it's to practice the suffix automaton

If you use SAM, you can build a SAM for the A string, and then let the B string run on the SAM. If a certain transfer \(c\) is mismatched, then it will be transferred along the suffix connection until the current node can match \(c\ ) . In this process, the length of the matched substring is maintained. If the transfer is successful, it will be \(+1\) , and moving along the suffix connection will become the \(max\) value of the current node (the maximum length of the string represented by the node)

But this time limit is too tight, and SPOJ is very slow... It needs a very good SAM implementation to pass this problem. I can't pass the board that uses Menci's dynamic application point to implement SAM. It seems that it must be written statically. After this question, I finally made a better SAM implementation on the blog :

#include <cstdio>
#include <cstring>
#include <algorithm>
using std::max;
using std::min;
using std::copy;
using std::fill;

const int MAX_N = 250009;

struct Node {
    static Node buf[], *bufp;
    void *operator new(size_t) {return bufp++;}

    int lim;
    Node *ch[26], *f;
    Node() = default;
    Node(int lim_): lim(lim_) {
        fill(ch, ch+26, nullptr);
    }
} Node::buf[MAX_N*4], *Node::bufp=buf, *root, *last;

void append(char c) {
    int x = c-'a';
    Node *now=new Node(last->lim+1), *p;
    for (p=last; p && !p->ch[x]; p=p->f)
        p->ch[x] = now;
    if (!p) {
        now->f = root;
    } else {
        Node *q = p->ch[x];
        if (q->lim == p->lim+1) {
            now->f = q;
        } else {
            Node *r = new Node(p->lim+1);
            copy(q->ch, q->ch+26, r->ch);
            r->f = q->f;
            q->f = now->f = r;
            for (; p && p->ch[x]==q; p=p->f)
                p->ch[x] = r;
        }
    }
    last = now;
}

char a[MAX_N], b[MAX_N];

int main() {
    scanf("%s%s", &a, &b);
    last = root = new Node(0);
    for (char *p=a; *p; ++p)
        append(*p);

    Node *now = root;
    int ans = 0, pref = 0;
    for (char *p=b; *p; ++p) {
        int x = *p-'a';
        for (; now && !now->ch[x]; now=now->f)
            ;
        if (!now) {
            now = root;
            pref = 0;
            continue;
        }
        pref = min(pref, now->lim)+1;
        ans = max(ans, pref);
        now = now->ch[x];
    }
    printf("%d\n", ans);
}

I used a lot of excellent techniques, such as overloading newoperators to implement memory pools, using pointers to traverse strings to find less once strlen, etc.

learn one.jpg

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326484606&siteId=291194637