bzoj 1212 [HNOI2004]L语言 AC自动机

题目链接

https://www.lydsy.com/JudgeOnline/problem.php?id=1212

做法

首先看到多个单词匹配就直接想到AC自动机了啊,然后把AC自动机建出来,做匹配的时候有点不同,以f[i]表示以i结尾的前缀能否匹配,然后我是在每个单词的结尾挂了个vector,表示这个节点结尾的单词长度,用fin[i][j]表示。
那么我们每走到一个节点,把fail指针都遍历一遍,然后对于这些节点,f[i]|=f[i-fin[i][j]],表示我在i-fin[i][j]最后插入我现在这个单词,如果i-fin[i][j]可以匹配,那么i就可以匹配了。
最后从后往前找到第一个f值为1的数输出就好了。

代码

#include<cstdio>
#include<algorithm>
#include<cctype>
#include<cstring>
#include<iostream>
#include<cmath>
#include<vector>
#define LL long long
#define N (1000005)
using namespace std;
int n,m; 
template <typename T> void read(T&t) {
    t=0;
    bool fl=true;
    char p=getchar();
    while (!isdigit(p)) {
        if (p=='-') fl=false;
        p=getchar();
    }
    do {
        (t*=10)+=p-48;p=getchar();
    }while (isdigit(p));
    if (!fl) t=-t;
}
struct node{
    int len,h,t,now,cnt;
    int fail[305],ch[305][26],fali[305],q[N];
    bool f[N];
    char c[N];
    vector <int> fin[N];
    void insert(){
        scanf("%s",c+1);
        len=strlen(c+1);
        now=0;
        for (int i=1;i<=len;i++){
            int tt=c[i]-'a';
            if (!ch[now][tt]) ch[now][tt]=++cnt;
            now=ch[now][tt];
        }
        fin[now].push_back(len);
    }
    void get(){
        h=t=0;
        for (int i=0;i<26;i++){
            if (ch[0][i]) q[++t]=ch[0][i];
        }
        while (h<t){
            int u=q[++h],y;
            for (int i=0;i<26;i++){
                if (y=ch[u][i]){
                    fail[y]=ch[fail[u]][i],q[++t]=y;
                }
                else ch[u][i]=ch[fail[u]][i];
            }
        }
    }
    void solve(){
        scanf("%s",c+1);
        int len=strlen(c+1),now=0;
        memset(f,0,sizeof(f));
        f[0]=1;
        for (int i=1;i<=len;i++){
            now=ch[now][c[i]-'a'];
            for (int t=now;t;t=fail[t]){
                for (int j=0;j<fin[t].size();j++){
                    if (f[i-fin[t][j]]){
                        f[i]=1;
                        break;
                    }
                }
            }   
        }
        for (int i=len;i>=0;i--){
            if (f[i]){
                printf("%d\n",i);
                return;
            }
        }
    }
}Tree;
int main(){
    read(n),read(m);
    for (int i=1;i<=n;i++) Tree.insert();
    Tree.get();
    for (int i=1;i<=m;i++){
        Tree.solve();
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_36056315/article/details/80785776