字符串训练之八

https://www.luogu.org/problem/P3966

分析:

比较普通的AC自动机,这个题唯一不同的就是询问有很多个,但询问的又是模式串

所以建完自动机后暴力询问肯定会Tle

考虑过程跳fail指针的过程

每一个节点保存一下属于多少字符串,为它的权值。

然后一个节点表示的字符串在整个字典中出现的次数相当于其在Fail树中的子树的权值的和

code :

include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 1100005
using namespace std;
int n,a[N],h[N],cnt,last,ch[N][26],sz[N],fail[N];
char s[N];
struct ac{
    void ins(int x){
        scanf("%s",s+1);int now=0,len=strlen(s+1);
        for(int i=1;i<=len;i++){
            int u=s[i]-'a';
            if(!ch[now][u]) ch[now][u]=++cnt;
            now=ch[now][u];
            sz[now]++;
        }
        a[x]=now;
    }
    void build(){
        int i,head=0,tail=0;
        for(i=0;i<26;i++) if(ch[0][i]) h[++tail]=ch[0][i];
        while(head<tail){
            int x=h[++head],y;
                for(i=0;i<26;i++) if(y=ch[x][i]){
                h[++tail]=y;
                fail[y]=ch[fail[x]][i];
            }
            else ch[x][i]=ch[fail[x]][i];
        }
    }
    void solve(){
        for(int i=cnt;i>=0;i--) sz[fail[h[i]]]+=sz[h[i]];
        for(int i=1;i<=n;i++) printf("%d\n",sz[a[i]]);
    }
}ac;
int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;i++) ac.ins(i);
    ac.build();ac.solve();
    return 0;
}

当然如果你不会AC自动机还有哈希的做法:

code:

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#define f(x,y,z) for(int x=y;x<=z;x++)
#define F(x,y,z,v) for(int x=y;x<=z;x+=v)
using namespace std;
const int MAXN=1000005;
char a[205][MAXN],b[MAXN<<1];
unsigned long long hash1[205],hash2[MAXN<<1],divi[MAXN<<1];
int stl[205];
const int BASE=131;
unsigned long long getsum(int l,int r)
{
    return hash2[r]-hash2[l-1]*divi[r-l+1];
}
int main()
{
    int n;
    scanf("%d",&n);
    int cnt=-1,len;
    f(i,1,n)
    {
        b[++cnt]='#';
        scanf("%s",&a[i]);
        len=strlen(a[i]);
        stl[i]=len;
        f(j,0,len-1)
        {
            b[++cnt]=a[i][j];
            hash1[i]*=BASE;
            hash1[i]+=a[i][j];
        }
    }
    len=strlen(b);
    hash2[0]=b[0];
    divi[0]=1;
    f(i,1,len-1)
    {
        hash2[i]=hash2[i-1]*BASE+b[i];
        divi[i]=divi[i-1]*BASE;
    }
    f(i,1,n)
    {
        int tcnt=0;
        f(j,1,len-stl[i])
            if(hash1[i]==getsum(j,j+stl[i]-1))
                tcnt++;
        printf("%d\n",tcnt);
    }
    return 0;
}
posted @ 2019-10-30 18:47  wzx_believer  阅读(125)  评论(0编辑  收藏  举报