HDU4622 Reincarnation

本文介绍了一种使用AC自动机进行子串统计的方法,通过固定左端点并依次加入子串来预处理所有可能的询问,实现O(1)查询效率。文章详细解释了如何构建AC自动机,并给出了完整的C++代码实现。

题目链接:戳我

因为对应的很多询问,所以我们一定要将每一种询问先处理出来,然后O(1)查询。

至于怎么处理出来子串的子串呢?

我们固定左端点,然后依次加入子串即可。然后统计的时候直接统计last那一个类的即可(因为只有last是真正新建出来的节点,多出来的本质不同的子串也是出现在这里面的),我们直接\(t[i].longest-t[i].shortest+1=t[i].len-t[t[i].ff].len\)即可。

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#define MAXN 2010
using namespace std;
int last=1,tot=1,T,len,n,m;
int ans[MAXN][MAXN];
char s[MAXN];
struct Node{int len,ff,ch[26];}t[MAXN<<1];
inline void extend(int c)
{
    int p=last,np=++tot;last=np;
    t[np].len=t[p].len+1;
    while(p&&!t[p].ch[c]) t[p].ch[c]=np,p=t[p].ff;
    if(!p) t[np].ff=1;
    else
    {
        int q=t[p].ch[c];
        if(t[q].len==t[p].len+1) t[np].ff=q;
        else
        {
            int nq=++tot;
            t[nq]=t[q],t[nq].len=t[p].len+1;
            t[np].ff=t[q].ff=nq;
            while(p&&t[p].ch[c]==q) t[p].ch[c]=nq,p=t[p].ff;
        }
    }
}
int main()
{
    #ifndef ONLINE_JUDGE
    freopen("ce.in","r",stdin);
    #endif
    scanf("%d",&T);
    while(T--)
    {
        memset(ans,0,sizeof(ans));
        last=tot=1;
        scanf("%s",s+1);
        len=strlen(s+1);
        for(int i=1;i<=len;i++)
        {
            memset(t,0,sizeof(t));
            tot=last=1;
            for(int j=i;j<=len;j++)
            {
                extend(s[j]-'a'+1);
                ans[i][j]=ans[i][j-1]+t[last].len-t[t[last].ff].len;
            }
        }
        scanf("%d",&m);
        for(int i=1;i<=m;i++)
        {
            int l,r;
            scanf("%d%d",&l,&r);
            printf("%d\n",ans[l][r]);
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/fengxunling/p/10749999.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值