【BZOJ1212】L语言(AC自动机)

【BZOJ1212】L语言(AC自动机)

题面

BZOJ

题解

很自然的,既然要匹配单词,那就全部都丢到\(AC\)自动机里面去

现在想想怎么匹配
先是\(AC\)自动机正常的匹配
如果此时这个位置能够匹配上一个串
我们就需要判断一下这个串覆盖到这个文本串中
它的前一位是否恰好被覆盖
如果有的话
我们也不能直接计算
因为可能是其他不同的串拼起来的
所以,就开一个数组差分
表示当前位置可以匹配

最后,对于每个文本串
从前往后扫一遍差分数组
直到有\(0\)的地方就直接输出就行啦

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<set>
#include<map>
#include<vector>
#include<queue>
using namespace std;
inline int read()
{
    int x=0,t=1;char ch=getchar();
    while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    if(ch=='-')t=-1,ch=getchar();
    while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    return x*t;
}
struct Node
{
    int vis[26];
    int dep,lst,fail;
}t[5000];
int n,m,tot;
char s[2000000];
int cc[2000000];
bool vis[2000000];
void insert(char *s)
{
    int l=strlen(s+1),now=0;
    for(int i=1;i<=l;++i)
    {
        if(!t[now].vis[s[i]-97])
            t[now].vis[s[i]-97]=++tot;
        now=t[now].vis[s[i]-97];
        t[now].dep=i;
    }
    t[now].lst=1;
}
void GetFail()
{
    queue<int> Q;
    for(int i=0;i<26;++i)
        if(t[0].vis[i])Q.push(t[0].vis[i]);
    while(!Q.empty())
    {
        int u=Q.front();Q.pop();
        for(int i=0;i<26;++i)
            if(t[u].vis[i])
                t[t[u].vis[i]].fail=t[t[u].fail].vis[i],Q.push(t[u].vis[i]);
            else t[u].vis[i]=t[t[u].fail].vis[i];
    }
}
int main()
{
    n=read();m=read();
    for(int i=1;i<=n;++i)
    {
        scanf("%s",s+1);
        insert(s);
    }
    GetFail();
    while(m--)
    {
        scanf("%s",s+1);
        int l=strlen(s+1);
        int lst=0,now=0;
        memset(cc,0,sizeof(cc));
        memset(vis,0,sizeof(vis));
        vis[0]=true;
        for(int i=1;i<=l;++i)
        {
            now=t[now].vis[s[i]-97];
            for(int j=now;j;j=t[j].fail)
                if(t[j].lst&&vis[i-t[j].dep])
                {
                    vis[i]=true;
                    cc[i-t[j].dep+1]++;
                    cc[i+1]--;
                }
        }
        for(int i=1,tot=0;i<=l;++i)
        {
            tot+=cc[i];
            if(tot)++lst;else break;
        }
        printf("%d\n",lst);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/cjyyb/p/8313084.html

时间: 2024-10-03 21:26:05

【BZOJ1212】L语言(AC自动机)的相关文章

BZOJ 1212: [HNOI2004]L语言 [AC自动机 DP]

1212: [HNOI2004]L语言 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 1367  Solved: 598[Submit][Status][Discuss] Description 标点符号的出现晚于文字的出现,所以以前的语言都是没有标点的.现在你要处理的就是一段没有标点的文章. 一段文章T是由若干小写字母构成.一个单词W也是由若干小写字母构成.一个字典D是若干个单词的集合. 我们称一段文章T在某个字典D下是可以被理解的,是指如果文

BZOJ 1212 HNOI2004 L语言 AC自动机(Trie树)+动态规划

题目大意:给定一个单词表和m个字符串 问每个字符串的最长的前缀,满足这个前缀可以拆分成一些字符串 使这些字符串都在单词表中出现过 再也不敢看错数据范围了--一道明明用Trie树能解决的问题居然被我写了AC自动机-- 将单词表中的单词全都插入AC自动机 每个单词所在的节点记录这个单词的长度 然后对于每个字符串 用f[i]表示长度为i的前缀是否能拆分成单词表中的单词 跑AC自动机 对于每个匹配的节点 从这个节点开始到根的fail路径上的所有len f[i]|=f[i-len] 找到最大的为1的f[i

bzoj1212 L语言

Description 标点符号的出现晚于文字的出现,所以以前的语言都是没有标点的.现在你要处理的就是一段没有标点的文章. 一段文章T是由若干小写字母构成.一个单词W也是由若干小写字母构成.一个字典D是若干个单词的集合. 我们称一段文章T在某个字典D下是可以被理解的,是指如果文章T可以被分成若干部分,且每一个部分都是字典D中的单词. 例如字典D中包括单词{‘is’, ‘name’, ‘what’, ‘your’},则文章‘whatisyourname’是在字典D下可以被理解的 因为它可以分成4个

bzoj 1212 [HNOI2004] L语言(不用AC自动机)

网上的题解大多树都要建一棵trie树,并在上面跑AC自动机,然而这里有一种同样需要trie树,但时间复杂度较低的方法. 首先,我们可以轻松列出状态转移方程 F[x]=∑| F[x-len(i)]&(is(i->x,s[i]); 这样的复杂度是O(m*lens*∑len[i]*n),可能会超时,再加上hash之类的就可以过了,但这显然不优美. ====================分割线==================== 对于每个F(i),我们都是从之前的额某个F(j)转移过来的,它是

1212: [HNOI2004]L语言

1212: [HNOI2004]L语言 Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 643  Solved: 252[Submit][Status] Description 标点符号的出现晚于文字的出现,所以以前的语言都是没有标点的.现在你要处理的就是一段没有标点的文章. 一段文章T是由若干小写字母构成.一个单词W也是由若干小写字母构成.一个字典D是若干个单词的集合. 我们称一段文章T在某个字典D下是可以被理解的,是指如果文章T可以被分成若干部

AC自动机总结

AC自动机总结 自动机的概念: 自动机又称有限状态机,是从初始状态不断接受输入,根据输入数据和当前状态跳转到下一状态的一种机器. AC自动机可以实现多串匹配单串.复杂度是\(O(n+m)\),也就是匹配串长+模式串总长. AC自动机匹配失配时,类似KMP算法的next数组,AC自动机上有fail指针可以跳到下一个应该进行匹配的状态. fail指针的一般定义是:沿着父亲的fail指针一直向上跳,直到跳到某一个节点,这个节点拥有与自己相同字母的子节点,那么fail指针就指向这个相同字母的子节点. 一

AC自动机 + 矩阵优化 --- [BJOI2017]魔法咒语

bzoj 4860   LOJ2180   洛谷P3175 [BJOI2017]魔法咒语 题目描述: Chandra 是一个魔法天才. 从一岁时接受火之教会洗礼之后,Chandra 就显示出对火元素无与伦比的亲和力,轻而易举地学会种种晦涩难解的法术. 这也多亏 Chandra 有着常人难以企及的语言天赋,让她能轻松流利地说出咒语中那些极其拗口的魔法词汇. 直到十四岁,开始学习威力强大的禁咒法术时,Chandra 才遇到了障碍. 根据火之魔法规则,禁咒的构成单位是 N 个基本词汇. 施法时只要凝聚

AC自动机--summer-work之我连模板题都做不出

这章对现在的我来说有点难,要是不写点东西,三天后怕是就一无所有了. 但写这个没有营养的blog的目的真的不是做题或提升,只是学习学习代码和理解一些概念. 现在对AC自动机的理解还十分浅薄,这里先贴上目前我看过的文章: 深入理解Aho-Corasick自动机算法 AC 自动机学习笔记 AC自动机相比Trie多了失配边,结点到结点间的状态转移,结点到根的状态转移. 这里fail的定义是:使当前字符失配时跳转到另一段从root开始每一个字符都与当前已匹配字符段某一个后缀完全相同且长度最大的位置继续匹配

暑假集训day9补充(AC自动机)

推荐网站http://blog.csdn.net/niushuai666/article/details/7002823 AC自动机嘛,此AC(aho-corasick)非彼AC(Accepted). 我也不是很会解释 有一题是必须打的hdu2222. #include<iostream> #include<cstdio> #include<cstring> #include<queue> using namespace std; const int mn=