【后缀自动机】51nod 淋漓尽致子串

通道

题意:最大周期串有多少个,子串不算。

思路:建好SAM后,fail和next跳,删除前缀相同和后缀相同即可

代码:

#include <cstdio>
#include <cstring>
#include <vector>
#include <map>
#include <string>
#include <algorithm>

using namespace std;

const int MAX_N = 200007;

typedef unsigned long long ll;

struct SAM {
    int val[MAX_N], fa[MAX_N], c[26][MAX_N];
    int tot, last;
    int which[MAX_N]; //该节点的字符 
    inline int newNode(int step) {
        val[++tot] = step;
        fa[tot] = 0;
        for (int i = 0; i < 26; ++i) c[i][tot] = 0;
        return tot;
    }
    inline void extend(int k) {
        int p = last;
        int np = newNode(val[last] + 1);
        which[np] = k;
        while (p && !c[k][p]) c[k][p] = np, p = fa[p];
        if (!p) fa[np] = 1;
        else {
            int q = c[k][p];
            if (val[q] == val[p] + 1) fa[np] = q;
            else {
                int nq = newNode(val[p] + 1);
                which[nq] = k;
                for (int i = 0; i < 26; ++i) c[i][nq] = c[i][q];
                fa[nq] = fa[q]; 
                fa[q] = fa[np] = nq;
                while (p && c[k][p] == q) c[k][p] = nq, p = fa[p];
            }
        }
        last = np;
    }
    inline int add(int k) {
        extend(k);
    }
    inline void init() {
        tot = 0;
        last = newNode(0);
    }
} suf;

char A[MAX_N>>1], B[MAX_N>>1];
int id[MAX_N], cnt[MAX_N], C[MAX_N];

int main() {
    scanf("%s", B);
    suf.init(); 
    for (int i = 0; B[i]; ++i) suf.add(B[i] - 'a');
    int len = strlen(B);
    for (int i = 1; i <= suf.tot; ++i) ++C[suf.val[i]];
    for (int i = 1; i <= len; ++i) C[i] += C[i - 1];
    for (int i = 1; i <= suf.tot; ++i) id[C[suf.val[i]]--] = i;
    int j = 1;
    for (int i = 0; i < len; ++i) {
        ++cnt[suf.c[B[i] - 'a'][j]];
        j = suf.c[B[i] - 'a'][j];
    }
    for (int i = suf.tot; i > 0; --i) {
        int d = id[i];
        cnt[suf.fa[d]] += cnt[d];
    }
    for (int i = 1; i <= suf.tot; ++i) {
        int d = id[i];
        for (int j = 0; j < 26; ++j) {
            if (suf.c[j][d] == 0) continue;
            if (cnt[suf.c[j][d]] > 1) {
                cnt[d] = 1;
                break;
            } 
        }
        while (d && cnt[suf.fa[d]] > 1) d = suf.fa[d], cnt[suf.fa[d]] = 1;
    }
    int ans = 0;
    for (int i = suf.tot; i > 1; --i) {
        if (cnt[i] > 1) 
            ++ans;
    }
    printf("%d\n", ans);
    return 0;
}
View Code

 

posted @ 2015-09-27 19:55  mithrilhan  阅读(223)  评论(0编辑  收藏  举报