HDU4622 (查询一段字符串的不同子串个数,后缀自动机)

Posted shuaihui

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU4622 (查询一段字符串的不同子串个数,后缀自动机)相关的知识,希望对你有一定的参考价值。

http://acm.hdu.edu.cn/showproblem.php?pid=4622

题意:给出一个字符串和q次询问,每次询问[l,r]区间内不同子串的个数

分析:

N<=2000.

我是用后缀自动机预处理出所有区间的不同子串个数。

建立n次后缀自动机。

为什么要建立N次呢? 因为鸭 , 后缀自动机之所以有继承性是因为定义的起点是相同的 , 而起点不同是没有继承性的  , 所以要枚举n次不同的节点建立后缀自动机。

用一个变量t , 不断的累加建立到当前点有多少个不同的字符串 , 就是前缀和的思想

技术图片
#include <bits/stdc++.h>
#define LL long long
#define P pair<int, int>
#define lowbit(x) (x & -x)
#define mem(a, b) memset(a, b, sizeof(a))
#define rep(i, a, n) for (int i = a; i <= n; ++i)
const int maxn = 2005;
#define mid ((l + r) >> 1)
#define lc rt<<1
#define rc rt<<1|1
using namespace std;

struct SAM{

    int trans[maxn<<1][26], slink[maxn<<1], maxlen[maxn<<1];
    int last, now, root, len;
    inline void newnode (int v) {
        maxlen[++now] = v;
    }

    inline int extend(int c) {
        newnode(maxlen[last] + 1);
        int p = last, np = now;
        // 更新trans
        while (p && !trans[p][c]) {
            trans[p][c] = np;
            p = slink[p];
        }
        if (!p) slink[np] = root;
        else {
            int q = trans[p][c];
            if (maxlen[p] + 1 != maxlen[q]) {
                // 将q点拆出nq,使得maxlen[p] + 1 == maxlen[q]
                newnode(maxlen[p] + 1);
                int nq = now;
                memcpy(trans[nq], trans[q], sizeof(trans[q]));
                slink[nq] = slink[q];
                slink[q] = slink[np] = nq;
                while (p!=-1 && trans[p][c] == q) {
                    trans[p][c] = nq;
                    p = slink[p];
                }
            }else slink[np] = q;
        }
        last = np;
        // 初始状态为可接受状态
        return maxlen[np]-maxlen[slink[np]];
    }
   inline void init()
   {
       memset(trans,0,sizeof(trans));
       memset(slink,0,sizeof(slink));
       memset(maxlen,0,sizeof(maxlen));
       root = last=now=1;
   }

}sam;
int ans[maxn][maxn];
int main()
{

    int t;scanf("%d",&t);
    while(t--)
    {
        string str;cin>>str;

        for(int i=0 ; i<str.size() ; i++)
        {
            sam.init();
            int T=0;
            for(int j=i ; j<str.size() ; j++)
            {
                T+=sam.extend(str[j]-a);
                ans[i+1][j+1]=T;
            }
        }
        int q;scanf("%d",&q);
        while(q--)
        {
            int u,v;scanf("%d%d",&u,&v);
            printf("%d
",ans[u][v]);
        }
    }



   //- sam.all();
}
View Code

 

以上是关于HDU4622 (查询一段字符串的不同子串个数,后缀自动机)的主要内容,如果未能解决你的问题,请参考以下文章

HDU 4622 Reincarnation (区间不相同子串个数:字符串哈希 | 后缀数组 | 后缀自动机)

HDU4622Reincarnation(后缀自动机)

HDU4622 Reincarnation 后缀自动机

HDU4622: Reincarnation

hdu4622(后缀自动机模板)

HDU 4622 Reincarnation(后缀自动机)