hdu 4622 Reincarnation 后缀自动机,记忆化

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4622

题目要求处理出询问的从i到j的子串的不同子串的数量,因为串长最大2000,所以n^2+记忆化处理出任意从i到j的不同子串数量(即每个节点的max-其父节点的max)

#include<bits/stdc++.h>
#include<iostream>
#define lan(a,b) memset(a,b,sizeof(a))

using namespace std;

//const int MAXN = 4e5+10;
//const int LetterSize = 26;
//
//int tot, last,ch[MAXN][LetterSize],fa[MAXN],len[MAXN];
//int ans=0;
//void init()
//{
//    last = tot = 1;
//    len[1] = 0;
//    memset(ch,0,sizeof ch);
//    memset(fa,0,sizeof fa);
//    ans=0;
//}
//
//int add( int x)
//{
//    int p = last, np = last = ++tot;
//    len[np] = len[p] + 1;
//    while( p && !ch[p][x]) ch[p][x] = np, p = fa[p];
//    if(p == 0) fa[np] = 1;
//    else
//    {
//        int q = ch[p][x];
//        if( len[q] == len[p] + 1)
//            fa[np] = q;
//        else
//        {
//            int nq = ++tot;
//            memcpy( ch[nq], ch[q], sizeof ch[q]);
//            len[nq] = len[p] + 1, fa[nq] = fa[q], fa[q] = fa[np] = nq;
//            while( p && ch[p][x] == q)  ch[p][x] = nq, p = fa[p];
//        }
//    }
//    ans+=len[last]-len[fa[last]];
//    return ans;
//}



char s[2010];
int dp[2010][2010];


typedef long long ll;
const int maxn = 4005;
const int SIGMA_SIZE = 26;

    int sz, last;
    int g[maxn<<1][SIGMA_SIZE], pre[maxn<<1], step[maxn<<1];
    int tot;

    void newNode(int s) {
        step[++sz] = s;
        pre[sz] = 0;
        memset(g[sz], 0, sizeof(g[sz]));
    }

    int idx(char ch) { return ch -'a'; }

    void init() {
        tot = 0;
        sz = 0, last = 1;
        newNode(0);
    }

    int insert(char ch) {
        newNode(step[last] + 1);
        int v = idx(ch), p = last, np = sz;

        while (p && !g[p][v]) {
            g[p][v] = np;
            p = pre[p];
        }

        if (p) {
            int q = g[p][v];
            if (step[q] == step[p] + 1)
                pre[np] = q;
            else {
                newNode(step[p] + 1);
                int nq = sz;
                for (int j = 0; j < SIGMA_SIZE; j++) g[nq][j] = g[q][j];

                pre[nq] = pre[q];
                pre[np] = pre[q] = nq;

                while (p && g[p][v] == q) {
                    g[p][v] = nq;
                    p = pre[p];
                }
            }
        } else
            pre[np] = 1;
        tot += step[np] - step[pre[np]];
        last = np;
        return tot;
    }

int main()
{
    int q,n,l,r;
    int t;
    scanf("%d",&t);
    while(t--)
    {
        lan(dp,0);
        scanf("%s",s);
        n=strlen(s);
        for(int i=0;i<n;i++)
        {
            init();
            for(int j=i;j<n;j++)
            {
                dp[i+1][j+1]+=insert(s[j]);

//            cout  <<i+1  << " " << j+1 << "= "<<  dp[i+1][j+1]  << endl;
            }
        }
        scanf("%d",&q);
        while(q--)
        {
            scanf("%d%d",&l,&r);
            printf("%d\n",dp[l][r]);
        }
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值