• 子串计数


    @(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
    ", 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();
    }
    
  • 相关阅读:
    我的架构经验小结(四)-- 实战中演化的三层架构
    DCFramework 动态分布式计算框架(01)-- 基础结构
    XNA基础(01) —— 游戏循环
    使用动态代理记录方法执行的时间
    高性能的大型系统经验 -- 数据查询与分页
    成功的捷径?
    如何激励你的员工?
    DCFramework 动态分布式计算框架(00) -- 序
    在应用程序之间传递动态程序集
    圈 Circle--ESBasic 可复用的.NET类库(03)
  • 原文地址:https://www.cnblogs.com/ZeonfaiHo/p/6719948.html
Copyright © 2020-2023  润新知