zoukankan      html  css  js  c++  java
  • BZOJ4516: [Sdoi2016]生成魔咒

    【传送门:BZOJ4516


    简要题意:

      给出一个长度为n的数字字符串,求出每个数字插入到字符串结尾时的不同子串个数


    题解:

      后缀自动机

      对于一个状态s,他的right集合代表的子串的长度就是(dep[fail],dep[s]]。这道题我们需要动态的维护不同子串的个数,每次从头扫一遍直接计算肯定不行,我们考虑加入一个新字符会产生多少新的不同子串,这个个数其实就是(dep[fail],dep[s]]的区间长度(自行yy吧)

      注意加long long,而且字符种数太多了,用map存


    参考代码:

    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<algorithm>
    #include<cmath>
    #include<map>
    using namespace std;
    typedef long long LL;
    map<int,int>tr[210000];
    int dep[210000],fail[210000],cnt,last,root;
    int a[110000];
    void add(int k)
    {
        int x=a[k];
        int np=++cnt,p=last;
        dep[np]=k;
        while(p!=0&&tr[p][x]==0) tr[p][x]=np,p=fail[p];
        if(p==0) fail[np]=root;
        else
        {
            int q=tr[p][x];
            if(dep[q]==dep[p]+1) fail[np]=q;
            else
            {
                int nq=++cnt;
                tr[nq]=tr[q];
                dep[nq]=dep[p]+1;
                fail[nq]=fail[q];
                fail[q]=fail[np]=nq;
                while(p!=0&&tr[p][x]==q) tr[p][x]=nq,p=fail[p];
            }
        }
        last=np;
    }
    int Rsort[110000],sa[210000],r[210000],sum[210000];
    int main()
    {
        int n;
        scanf("%d",&n);
        cnt=last=root=1;
        LL ans=0;
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
            add(i);
            ans+=dep[last]-dep[fail[last]];
            printf("%lld
    ",ans);
        }
        return 0;
    }

     

  • 相关阅读:
    C#与SAP进行数据交互
    自动加减工单结存算法实现
    RDLC报表打印一维码
    调用存储过程通用类
    监听网络状态
    压缩及解压缩文件
    用Go造轮子-管理集群中的配置文件
    2015年总结
    浅析Go语言的Interface机制
    2014年总结
  • 原文地址:https://www.cnblogs.com/Never-mind/p/8805705.html
Copyright © 2011-2022 走看看