子串计数

@(XSY)[后缀自动机]

题面

题目描述

给定n个仅有小写字母组成的字符串,求所有这些字符串中不同的子串的个数。

输入描述

第一行一个正整数n。
接下来n行每行一个字符串。

输出描述

一行一个整数,表示答案。

数据范围

共两个subtask。
所有字符串的总长不超过105。
Subtask 1
n=1
subtask 2
n≤10000

Soltion

广义后缀自动机乱搞

/*
线性构造
自带26巨大常数
绝望啊 
*/

#include <cstdio>
#include <cctype>
#include <cstring>
 
const int LEN = (int)1e5;
 
namespace Zeonfai
{
    inline int getInt()
    {
        int a = 0, sgn = 1;
        char c;
 
        while(! isdigit(c = getchar()))
            if(c == '-')
                sgn *= -1;
 
        while(isdigit(c))
            a = a * 10 + c - '0', c = getchar();
 
        return a * sgn;
    }
 
    inline int getString(char *str)
    {
        char c;
 
        while(! isgraph(c = getchar()));
 
        int len = 0;
 
        while(isgraph(c))
            str[len ++] = c, c = getchar();
 
        return len;
    }
}
 
struct suffixAutomaton
{
    struct state
    {
        int suc[26], pre, len;
 
        inline state()
        {
            memset(suc, -1, sizeof(suc));
            pre = -1;
            len = 0;
        }
    }nd[LEN << 1];
 
    int tp, s, lst;
 
    inline void initialize()
    {
        s = lst = 0;
        tp = 1;
    }
 
    inline void newString()
    {
        lst = s;
    }
 
    inline void insert(int c)
    {
        int u = tp ++, pre = lst;
        nd[u].len = nd[pre].len + 1;
 
        for(; ~ pre && nd[pre].suc[c] == -1; nd[pre].suc[c] = u, pre = nd[pre].pre);
 
        if(pre == -1)
            nd[u].pre = s;
        else
        {
            int preSuc = nd[pre].suc[c];
 
            if(nd[preSuc].len == nd[pre].len + 1)
                nd[u].pre = preSuc;
            else
            {
                int v = tp ++;
                nd[v] = nd[preSuc];
                nd[v].len = nd[pre].len + 1;
                nd[u].pre = nd[preSuc].pre = v;
                 
                for(; ~ pre && nd[pre].suc[c] == preSuc; nd[pre].suc[c] = v, pre = nd[pre].pre);
            }
        }
 
        lst = u;
    }
 
    inline void getAnswer()
    {
        long long ans = 0;
         
        for(int i = 1; i < tp; ++ i)
            ans += nd[i].len - nd[nd[i].pre].len;
         
        printf("%lld\n", ans);
    }
}SAM;
 
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("SAM.in", "r", stdin);
    freopen("SAM.out", "w", stdout);
    #endif
 
    using namespace Zeonfai;
    int n = getInt();
    SAM.initialize();
 
    for(int i = 0; i < n; ++ i)
    {
        static char str[LEN];
//        int len = getString(str);
		gets(str);
		int len = strlen(str);
        SAM.newString();
 
        for(int i = 0; i < len; ++ i)
            SAM.insert(str[i] - 'a');
    }
 
    SAM.getAnswer();
}
posted @ 2017-04-16 21:01  Zeonfai  阅读(347)  评论(0编辑  收藏  举报