后缀机

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

struct Node {
    int len, link, ch[26];
    //额外信息
    int cnt, head;
    void NewNode(int l = 0) {
        len = l, memset(ch, 0, sizeof(ch)), link = 0;
        cnt = 1, head = 0;
    }
    void CopyNewNode(const int &l, const Node& n) {
        len = l, memcpy(ch, n.ch, sizeof(ch)), link = n.link;
        cnt = 0, head = 0;
    }
};

const int MAXN = 1000000;

struct Edge {
    int to, next;
} edge[(MAXN << 1) + 5];
int etop;

//SuffixAutomaton
struct SAM {
    Node nd[(MAXN << 1) + 5];
    int top, last;  //top为节点个数,last末尾节点的位置

    void init() {
        nd[1].NewNode();
        top = 1;
    }

    void extend(char ch) {
        int c = ch - 'a';
        int p = last, x = last = ++top;
        nd[x].NewNode(nd[p].len + 1);
        for(; p && !nd[p].ch[c]; p = nd[p].link)
            nd[p].ch[c] = x;
        if(!p)
            nd[x].link = 1;
        else {
            int q = nd[p].ch[c];
            if(nd[p].len + 1 == nd[q].len)
                nd[x].link = q;
            else {
                int y = ++top;
                nd[y].CopyNewNode(nd[p].len + 1, nd[q]);
                nd[q].link = nd[x].link = y;
                for(; p && nd[p].ch[c] == q; p = nd[p].link)
                    nd[p].ch[c] = y;
            }
        }
    }

    void dfs(int id) {
        for(int i = nd[id].head; i; i = edge[i].next) {
            dfs(edge[i].to);
            nd[id].cnt += nd[edge[i].to].cnt;
        }
    }

    ll solve() {
        //计算每一种子串的数量
        etop = 0;
        for(int i = top; i >= 2; --i) {
            ++etop;
            edge[etop].to = i;
            edge[etop].next = nd[nd[i].link].head;
            nd[nd[i].link].head = etop;
        }
        dfs(1);
        ll res = 0;
        for(int i = top; i >= 2; --i)
            if(nd[i].cnt > 1) {
                ll tmp = 1ll * nd[i].cnt * nd[i].len;
                if(tmp > res)
                    res = tmp;
            }
        return res;
    }
} sam;

char s[MAXN + 5];

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    scanf("%s", s);
    sam.init();
    for(int i = 0; s[i] != '\0'; ++i)
        sam.extend(s[i]);
    printf("%lld\n", sam.solve());
}

这个link树不如回文机优美,但是可以用拓扑排序来非递归求。

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

struct Node {
    int len, link, ch[26];
    //额外信息
    int cnt;
    void NewNode(int l = 0) {
        len = l, memset(ch, 0, sizeof(ch)), link = 0;
        cnt = 1;
    }
    void CopyNewNode(const int &l, const Node& n) {
        len = l, memcpy(ch, n.ch, sizeof(ch)), link = n.link;
        cnt = 0;
    }
};

const int MAXN = 1000000;

//SuffixAutomaton
struct SAM {
    Node nd[(MAXN << 1) + 5];
    int top, last;  //top为节点个数,last末尾节点的位置

    void init() {
        nd[1].NewNode();
        top = 1;
    }

    void extend(char ch) {
        int c = ch - 'a';
        int p = last, x = last = ++top;
        nd[x].NewNode(nd[p].len + 1);
        for(; p && !nd[p].ch[c]; p = nd[p].link)
            nd[p].ch[c] = x;
        if(!p)
            nd[x].link = 1;
        else {
            int q = nd[p].ch[c];
            if(nd[p].len + 1 == nd[q].len)
                nd[x].link = q;
            else {
                int y = ++top;
                nd[y].CopyNewNode(nd[p].len + 1, nd[q]);
                nd[q].link = nd[x].link = y;
                for(; p && nd[p].ch[c] == q; p = nd[p].link)
                    nd[p].ch[c] = y;
            }
        }
    }

    int d[(MAXN << 1) + 5];
    int que[(MAXN << 1) + 5], front, back;

    ll solve() {
        //计算每一种子串的数量
        memset(d, 0, sizeof(d));
        front = 1, back = 0;
        for(int i = top; i >= 2; --i)
            ++d[nd[i].link];
        for(int i = top; i >= 2; --i)
            if(!d[i])
                que[++back] = i;
        while(back >= front) {
            int u = que[front], v = nd[que[front]].link;
            nd[v].cnt += nd[u].cnt;
            --d[v];
            if(!d[v])
                que[++back] = v;
            ++front;
        }
        ll res = 0;
        for(int i = top; i >= 2; --i)
            if(nd[i].cnt > 1) {
                ll tmp = 1ll * nd[i].cnt * nd[i].len;
                if(tmp > res)
                    res = tmp;
            }
        return res;
    }
} sam;

char s[MAXN + 5];

int main() {
#ifdef Yinku
    freopen("Yinku.in", "r", stdin);
#endif // Yinku
    scanf("%s", s);
    sam.init();
    for(int i = 0; s[i] != '\0'; ++i)
        sam.extend(s[i]);
    printf("%lld\n", sam.solve());
}

猜你喜欢

转载自www.cnblogs.com/Yinku/p/11257552.html