BZOJ 2780: [Spoj]8093 Sevenk Love Oimaster(广义后缀自动机)

Description:

Oimaster and sevenk love each other.
But recently,sevenk heard that a girl named ChuYuXun was dating with oimaster.As a woman’s nature, sevenk felt angry and began to check oimaster’s online talk with ChuYuXun. Oimaster talked with ChuYuXun n times, and each online talk actually is a string.Sevenk asks q questions like this, “how many strings in oimaster’s online talk contain this string as their substrings?”
有n个大串和m个询问,每次给出一个字符串s询问在多少个大串中出现过

Input

There are two integers in the first line,
the number of strings n and the number of questions q.
And n lines follow, each of them is a string describing oimaster’s online talk.
And q lines follow, each of them is a question.
n<=10000, q<=60000
the total length of n strings<=100000,
the total length of q question strings<=360000


题解:

求单个字符串是多个字符串的子串,当然是广义后缀自动机啦。

最后求的是询问串在所有大串中的总共出现次数,加一个cnt数组表示当前串的总共出现次数,还有一个vis数组表示当前后缀自动机中的节点最后一次是属于哪一个串的,如果不属于这次添加的串,更新vis和cnt即可。

AC代码:

#include<bits/stdc++.h>
using namespace std;
const int MAXN = 4e5+50;
int nxt[MAXN][26],fa[MAXN],len[MAXN];
int vis[MAXN],cnt[MAXN];
int last=1,tot=1;
char s[MAXN];
inline void Insert(int x,int id){
    int p=last,np=++tot;
    last=np,len[np]=len[p]+1;
    for(;p&&!nxt[p][x];p=fa[p]) nxt[p][x]=np;
    if(!p) fa[np]=1;
    else{
        int q = nxt[p][x];
        if(len[p]+1==len[q]) fa[np]=q;
        else{
            int nq = ++tot;
            cnt[nq]=cnt[q]; len[nq]=len[p]+1;
            memcpy(nxt[nq],nxt[q],sizeof(nxt[q]));
            vis[nq]=vis[q];
            fa[nq]=fa[q];
            fa[q]=fa[np]=nq;
            for(;p && nxt[p][x]==q;p=fa[p]) nxt[p][x]=nq;
        }
    }
    for(int p=np;p && vis[p]!=id;p=fa[p]) vis[p]=id,cnt[p]++;
}
int main(){
    int n,m; scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++){
        scanf("%s",s);
        last = 1;
        int l = strlen(s);
        for(int j=0;j<l;j++) Insert(s[j]-'a',i);
    }
    while(m--){
        scanf("%s",s);
        int l = strlen(s),rt = 1;
        for(int i=0;i<l;i++) rt = nxt[rt][s[i]-'a'];
        printf("%d\n",cnt[rt]);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值