Searching the String - ZOJ 3228(ac自动机)

题目大意:首先给你一下母串,长度不超过10^5,然后有 N(10^5) 次查询,每次查询有两种命令,0或者1,然后加一个子串,询问母串里面有多少个子串,0表示可以重复,1表示不可以重复。

 

分析:发现查询的次数是比较多的,然后可以利用查询的串建立一个trie,然后用母串跑一遍就行了,不过有两种操作比较麻烦一些,不过我们可以保存查询时每个节点的查询结果,然后每个串都对应一个节点,最后输出查询结果即可,这样也可以规避掉重复串的问题。

 

代码如下:

===============================================================================================================

#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
#include<queue>
using namespace std;

const int MAXN = 6e5+7;
const int MaxSon = 26;

char MumStr[MAXN];
int Num[MAXN], op[MAXN];

struct Ac_Trie
{
    int next[MAXN][MaxSon];
    int Fail[MAXN];
    ///End保存每个单词匹配成功后最后面的位置
    ///如果这个节点是一个单词,Len保存这个单词的长度
    int End[MAXN], Len[MAXN];
    int ans[MAXN][2];///保存两种状态的答案
    int root, cnt;

    int newnode()
    {
        for(int i=0; i<MaxSon; i++)
            next[cnt][i] = -1;
        Len[cnt] = Fail[cnt] = false;
        End[cnt] = -10;
        ans[cnt][0] = ans[cnt][1] = 0;

        return cnt++;
    }
    void InIt()
    {
        cnt = 0;
        root = newnode();
    }
    int Insert(char s[])
    {///返回这个字符串对应的节点编号
        int i, now = root;

        for(i=0; s[i]; i++)
        {
            int k = s[i] - ‘a‘;

            if(next[now][k] == -1)
                next[now][k] = newnode();
            now = next[now][k];
        }

        Len[now] = i;

        return now;
    }
    void GetFail()
    {
        queue<int> Q;
        int i, now = root;

        for(i=0; i<MaxSon; i++)
        {
            if(next[now][i] == -1)
                next[now][i] = root;
            else
            {
                Fail[next[now][i]] = root;
                Q.push(next[now][i]);
            }
        }

        while(Q.size())
        {
            now = Q.front();
            Q.pop();

            for(i=0; i<MaxSon; i++)
            {
                if(next[now][i] == -1)
                    next[now][i] = next[Fail[now]][i];
                else
                {
                    Fail[next[now][i]] = next[Fail[now]][i];
                    Q.push(next[now][i]);
                }
            }
        }
    }
    void Query(char MumStr[])
    {
        int i, now = root, temp;

        for(i=0; MumStr[i]; i++)
        {
            int k = MumStr[i] - ‘a‘;

            now = next[now][k];

            if(!now)continue;

            temp = now;

            while(temp != root)
            {
                if(Len[temp])
                    ans[temp][0]++;
                if(Len[temp] && (i-End[temp] >= Len[temp]) )
                    ans[temp][1]++, End[temp] = i;

                temp = Fail[temp];
            }
        }
    }
};
Ac_Trie ac;
int main()
{
    int i, M, t=1;

    while(scanf("%s", MumStr) != EOF)
    {
        char s[10];
        ac.InIt();

        scanf("%d", &M);

        for(i=1; i<=M; i++)
        {
            scanf("%d%s", &op[i], s);
            Num[i] = ac.Insert(s);
        }

        ac.GetFail();
        ac.Query(MumStr);

        printf("Case %d\n", t++);
        for(i=1; i<=M; i++)
            printf("%d\n", ac.ans[Num[i]][op[i]]);
        printf("\n");
    }

    return 0;
}
时间: 2024-10-07 20:39:35

Searching the String - ZOJ 3228(ac自动机)的相关文章

Searching the String ZOJ - 3228 AC自动机查询升级版

题意:先给你一个不超过1000000长度的大串s:接下来输入一个n代表接下来输入的小串个数,小串长度不超过6. 小串分两种类型0和1类型. 0类型表示小串在大串中的最大匹配个数就是常规的AC自动机的做法. 1类型表示小串在大串中不能重合的最大匹配数. 依次输出结果.(所有的串只包含小写字母) 按样例输出,注意每组测试数据后有一个换行. 题意我不想写了抄的,抄这里的 (不好意思啦) 0 类型的就是最开始的模板题 1 类型的处理方式就是,在建立字典树的时候弄一个dep数组,记录每一个节点的深度 然后

ZOJ 3430 AC自动机

http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=4114 Nobita did use an outstanding anti-virus software, however, for some strange reason, this software did not check email attachments. Now Nobita decide to detect viruses in emails by himse

ZOJ 3494 (AC自动机+高精度数位DP)

题目链接:  http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3494 题目大意:给定一些被禁止的BCD码.问指定范围内不含有任何这些禁止的BCD码的数的个数. 解题思路: AC自动机部分: 首先insert这些被禁止的BCD码. 然后打一下自动机前后状态的转移的表,用BCD[i][j]表示自动机状态i时,下一个数字是j的自动机的下一个状态. 一开始我考虑最先dfs的位在自动机的位置,后来发现SB了.AC自动机有一个roo

LA 4670 Dominating Patterns (AC自动机)

题意:给定n个字符串和一个文本串,查找哪个字符串出现的次数的最多. 析:一匹配多,很明显是AC自动机.只需要对原来的进行修改一下,就可以得到这个题的答案, 计算过程中,要更新次数,并且要映射字符串.如果用KMP肯定会超时. 代码如下: #include <iostream> #include <cstdio> #include <cstring> #include <map> #include <string> #include <queu

zoj 3228 Searching the String(AC自动机)

题目连接:zoj 3228 Searching the String 题目大意:给定一个字符串,然后现在有N次询问,每次有一个type和一个子串,问说子串在字符串中出现几次,type 为0时为可重叠,为1时为不可重叠. 解题思路:不过没有type=1的限制,那么就是普通的AC自动机匹配问题,对于不可重叠问题,可以对于每个节点记录 一下上一次匹配到的pos,用当前匹配的i减掉pos看有没有超过长度,有超过即为合法匹配,否则忽略. 题目中有很多相同的子串,一开始我用jump数组用类似链表的形式记录每

ZOJ 题目3228 Searching the String(AC自动机)

Searching the String Time Limit: 7 Seconds      Memory Limit: 129872 KB Little jay really hates to deal with string. But moondy likes it very much, and she's so mischievous that she often gives jay some dull problems related to string. And one day, m

ZOJ 3228 Searching the String (AC自己主动机)

题目链接:Searching the String 解析:给一个长串.给n个不同种类的短串.问分别在能重叠下或者不能重叠下短串在长串中出现的次数. 能重叠的已经是最简单的AC自己主动机模板题了. 不能重叠的记录一下每一个匹配的串的起始位置保证不重叠就可以. AC代码: #include <bits/stdc++.h> using namespace std; struct Trie{ int next[600010][26], fail[600010], deep[600010]; int r

AC自动机---Searching the String

ZOJ   3228 题目网址:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=16401 Description Little jay really hates to deal with string. But moondy likes it very much, and she's so mischievous that she often gives jay some dull problems related to

ZOJ3228 Searching the String (AC自动机)

Searching the String Time Limit: 7 Seconds                                      Memory Limit: 129872 KB Little jay really hates to deal with string. But moondy likes it very much, and she's so mischievous that she often gives jay some dull problems r