其他分享
首页 > 其他分享> > [HNOI2004] L语言 - AC自动机,dp

[HNOI2004] L语言 - AC自动机,dp

作者:互联网

给定字典和没有标点的文章,求能够被识别的最长前缀。

显然不能贪心,设\(f[i]\)表示前\(i\)个字符构成的前缀能否被识别,然后在AC自动机上暴力转移即可。

具体来说,每走到一个新位置,就沿着fail链把所有能转移的都转移了。

(突然发现我以前的AC自动机模板好像又有点锅?)

#include <bits/stdc++.h>
using namespace std;

const int N = 1000005;

int ch[N][26],dep[N],fi[N],val[N],n,m,t1,t2,t3,t4,ind;
int f[N];

void ins(char *s) {
    int len=strlen(s),p=0;
    for(int i=0;i<len;i++) {
        if(ch[p][s[i]-'a']==0) ch[p][s[i]-'a']=++ind;
        p=ch[p][s[i]-'a'];
        dep[p]=i+1;
    }
    val[p]++;
}

void build() {
    queue <int> q;
    for(int i=0;i<26;i++) if(ch[0][i]) q.push(ch[0][i]);
    while(!q.empty()) {
        int p=q.front(); q.pop();
        for(int i=0;i<26;i++)
            if(ch[p][i]) fi[ch[p][i]]=ch[fi[p]][i],q.push(ch[p][i]);
            else ch[p][i]=ch[fi[p]][i];
    }
}

int query(char *s) {
    int ans=0,len=strlen(s),p=0;
    for(int i=0;i<len;i++) {
        p=ch[p][s[i]-'a'];
        for(int t=p;t;t=fi[t])
            if(val[t]) f[i+1]|=f[i+1-dep[t]];
    }
    for(int i=1;i<=len;i++) if(f[i]) ans=i;
    return ans;
}

char str[N];

int main() {
    cin>>n>>m;
    for(int i=1;i<=n;i++) cin>>str,ins(str);
    build();
    for(int i=1;i<=m;i++) {
        memset(f,0,sizeof f);
        f[0]=1;
        cin>>str;
        cout<<query(str)<<endl;
    }
}

标签:AC,前缀,int,ins,HNOI2004,str,自动机,dp
来源: https://www.cnblogs.com/mollnn/p/12251370.html