hdu4416——后缀自动机

来源:互联网 发布:知乎书单 编辑:程序博客网 时间:2024/06/05 06:52

题意:问给定的字符串(S)有多少个不同的子串满足不是另外给定的一组字符串(T1~Tn)中任何一个串的子串。

把T中的字符串依次拿去和S的自动机匹配。每次匹配到一个状态,更新这个状态所匹配的最大的长度p,那么这个状态所表示的子串中长度大于p的即为我们要找的。在计算答案的时候,我们还要同时更新目前状态的pre状态的p值,所以要按逆拓扑序计算总答案。

#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>#define lng long longusing namespace std;const int maxn = 200000 + 10;int str[maxn];int len;struct suffix_automaton{    int ch[maxn][27], pre[maxn], val[maxn];    int c[maxn], top[maxn], p[maxn];    int sz, last;        void init()    {        pre[0] = -1; last = 0; sz = 1;        memset(ch[0], 0, sizeof(ch[0]));        memset(p, 0, sizeof(p));    }        void insert(int x)    {        int p = last, np = sz++;        last = np;        memset(ch[np], 0, sizeof(ch[np]));        val[np] = val[p] + 1;        while(p != -1 && ch[p][x] == 0)        {            ch[p][x] = np;            p = pre[p];        }        if(p == -1) pre[np] = 0;        else        {            int q = ch[p][x];            if(val[q] == val[p] + 1) pre[np] = q;            else            {                int nq = sz++;                memcpy(ch[nq], ch[q], sizeof(ch[q]));                val[nq] = val[p] + 1;                pre[nq] = pre[q];                pre[q] = pre[np] = nq;                while(p != -1 && ch[p][x] == q) { ch[p][x] = nq; p = pre[p]; }            }        }    }        void update(char * s)    {        int l = 0, u = 0;        for(int i = 0; s[i]; ++i)        {            int x = s[i] - 'a';            if(ch[u][x])            {                u = ch[u][x];                l++;            }            else            {                while(u != -1 && ch[u][x] == 0) u = pre[u];                if(ch[u][x]) { l = val[u]; u = ch[u][x]; l++; }                else u = 0, l = 0;            }            p[u] = max(p[u], l);        }    }        void solve()    {        memset(c, 0, sizeof(c));        for(int i = 0; i < sz; ++i) c[val[i]] += 1;        for(int i = 1; i <= len; ++i) c[i] += c[i - 1];        for(int i = 0; i < sz; ++i) top[--c[val[i]]] = i;        lng ans = 0;        for(int i = sz - 1; i > 0; --i)        {            int u = top[i];            if(p[u] < val[u])            {                int tmp = max(p[u], val[pre[u]]);                ans += val[u] - tmp;            }            p[pre[u]] = max(p[pre[u]], p[u]);        }        printf("%I64d\n", ans);    }    }sam;char s[maxn];void prework(){    int q; scanf("%d", &q);    scanf("%s", s); len = strlen(s);    sam.init();    for(int i = 0; i < len; ++i) { str[i] = s[i] - 'a'; sam.insert(str[i]); }    while(q--)    {        scanf("%s", s);        sam.update(s);    }}void solve(){    sam.solve();}int main(){    freopen("in.txt", "r", stdin);    int t; cin >> t;    int cc = 1;    while(t--)    {        prework();        printf("Case %d: ", cc++);        solve();    }    return 0;}


原创粉丝点击