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 related to string. And one day, moondy gave jay another problem, poor jay finally broke out and cried, " Who can help me? I‘ll bg him! "

So what is the problem this time?

First, moondy gave jay a very long string A. Then she gave him a sequence of very short substrings, and asked him to find how many times each substring appeared in string A. What‘s more, she would denote whether or not founded appearances of this substring are allowed to overlap.

At first, jay just read string A from begin to end to search all appearances of each given substring. But he soon felt exhausted and couldn‘t go on any more, so he gave up and broke out this time.

I know you‘re a good guy and will help with jay even without bg, won‘t you?

Input

Input consists of multiple cases( <= 20 ) and terminates with end of file.

For each case, the first line contains string A ( length <= 10^5 ). The second line contains an integer N ( N <= 10^5 ), which denotes the number of queries. The next N lines, each with an integer type and a string a ( length <= 6 ), type = 0 denotes substring a is allowed to overlap and type = 1 denotes not.  Note that all input characters are lowercase.

There is a blank line between two consecutive cases.

Output

For each case, output the case number first ( based on 1 , see Samples ).

Then for each query, output an integer in a single line denoting the maximum times you can find the substring under certain rules.

Output an empty line after each case.

Sample Input

ab
2
0 ab
1 ab

abababac
2
0 aba
1 aba

abcdefghijklmnopqrstuvwxyz
3
0 abc
1 def
1 jmn

Sample Output

Case 1
1
1

Case 2
3
2

Case 3
1
1
0

Hint

In Case 2,you can find the first substring starting in position (indexed from 0) 0,2,4, since they‘re allowed to overlap.  The second substring starts in position 0 and 4, since they‘re not allowed to overlap.

For C++ users, kindly use scanf to avoid TLE for huge inputs.

题意:多组数据,首先一串母串,下面是n个模式串,统计各模式串在母串中出现的个数,0表示模式串可交叉,1表示不可以交叉。

思路:0的时候就是普通ac自动机,1的时候有点麻烦。。我干啥用指针。。

   还是统计重复模式串的ans数组,这次得开二维,因为相同的模式串可能有两种情况。在不可交叉的情况下,我们发现一个模式串能再次被统计仅当  本次查找成功的位置-它上次的末尾位置≥查找结束时该字母在字典树的深度。

   其实就是判交叉。。比如ababa(下标从0开始)找aba,第二次查到4处,上次末尾在2,深度3,4-2<3,交叉。

   给每个节点一个编号id用来区分,于是可以用pos数组记录每个模式串的结尾区分模式串,方便最后统计ans,因为这次每个模式串可以有0和1两种形态。loc数组用来记录字典树节点们的深度,last数组记录上一次的统计末尾处,配合loc可以判交叉。

   (枯了 好像数组方便得多)

代码:

#include<bits/stdc++.h>
#define FastIO ios_base::sync_with_stdio(false), cin.tie(NULL), cout.tie(NULL);
#define inf 0x3f3f3f3f
#define rep(i,a,b) for(ll i=a;i<b;i++)
#define repp(i,a,b) for(ll i=a;i<=b;i++)
#define rep1(i,a,b) for(ll i=a;i>=b;i--)
#define mem(gv) memset(gv,0,sizeof(gv))
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define QAQ 0
#define miaojie
#ifdef miaojie
  #define dbg(args...) do {cout << #args << " : "; err(args);} while (0)
#else
  #define dbg(...)
#endif
void err() {std::cout << std::endl;}
template<typename T, typename...Args>
void err(T a, Args...args){std::cout << a << ‘ ‘; err(args...);}

using namespace std;
typedef long long ll;
typedef pair<int,int> pii;
typedef pair<ll,ll> pLL;
const int mod=1e9+7;
const int maxn=7e5+5;

int idd;
struct node
{
    node *fail;
    node *child[26];
    int id;
    node()
    {
        fail=NULL;
        id=idd++;
        for(int i=0;i<26;i++)
            child[i]=NULL;
    }
};
int n,op[maxn];
int ans[maxn][2],pos[maxn],last[maxn],loc[maxn];
char s1[maxn][9];
char s2[maxn];
node *rt;

void insert(node *t,char p[],int num)
{
    int index,lp=strlen(p),q=0;
    while(p[q]!=‘\0‘)
    {
        index=p[q]-‘a‘;
        if(t->child[index]==NULL)
            t->child[index]=new node();
        t=t->child[index];
        loc[t->id]=q+1;
        q++;
    }
    pos[num]=t->id;
}

void ac(node *t)
{
    queue <node*> q;
    t->fail=NULL;
    q.push(t);
    node *temp;
    node *tmp;
    int i;
    while(!q.empty())
    {
        temp=q.front();
        q.pop();
        for(i=0;i<26;i++)
        {
            if(temp->child[i]!=NULL)
            {
                if(temp==t)
                    temp->child[i]->fail=t;
                else
                {
                    tmp=temp->fail;
                    while(tmp!=NULL)
                    {
                        if(tmp->child[i]!=NULL)
                        {
                            temp->child[i]->fail=tmp->child[i];
                            break;
                        }
                        tmp=tmp->fail;
                    }
                    if(tmp==NULL)
                        temp->child[i]->fail=t;
                }
                q.push(temp->child[i]);
            }
        }
    }
}

void query(node *t)
{
    memset(last,-1,sizeof(last));
    mem(ans);
    int index,q=0,len=strlen(s2);
    node *p=t;
    while(s2[q])
    {
        index=s2[q]-‘a‘;
        while(p->child[index]==NULL &&p!=rt)
            p=p->fail;
        p=p->child[index];
        if(!p) p=rt;
        node *tmp=p;
        while(tmp!=rt)
        {
            ans[tmp->id][0]++;
            if(q-last[tmp->id]>=loc[tmp->id]){
                ans[tmp->id][1]++;
                last[tmp->id]=q;
            }
            tmp=tmp->fail;
        }
        q++;
    }
}

void del(node *root)
{
    for(int i=0;i<26;i++)
        if(root->child[i]!=NULL)
            del(root->child[i]);
    delete root;
    root=NULL;
}

int main(){
    int T=1;
    while(scanf("%s",s2)!=EOF){
        mem(pos); mem(loc); idd=0;
        rt=new node();
        scanf("%d",&n);
        repp(i,0,n-1){
            scanf("%d",&op[i]);
            scanf("%s",s1[i]);
            insert(rt,s1[i],i);
        }
        ac(rt);
        query(rt);
        printf("Case %d\n",T++);
        repp(i,0,n-1){
            printf("%d\n",ans[pos[i]][op[i]]);
        }
        del(rt);
        printf("\n");
    }
    return QAQ;
}

原文地址:https://www.cnblogs.com/miaomiaojie/p/10816397.html

时间: 2024-08-29 15:09:59

ZOJ3228 Searching the String (AC自动机)的相关文章

ZOJ3228 Searching the String AC自动机

题意:给你一个文本串,其中模式串有两种模式,可以重复和不可以重复,分别有多少个模式串 解题思路: 在  Trie 里面多加几维数组来维护 重复和不重复的和,由于不够优美,差点超内存. 解题代码: 1 // File Name: temp.cpp 2 // Author: darkdream 3 // Created Time: 2014年09月11日 星期四 15时18分4秒 4 5 #include<vector> 6 #include<list> 7 #include<m

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自动机的不重复匹配

这个判断方法真的没想到... 对于在S中匹配M,如果M上一次的匹配位置pre与这一次的匹配位置now满足now-pre >= M.length,则加1. 这个判断太跳了233 . #include <iostream> #include<time.h> #include<stdio.h> #include<string.h> #include<stdlib.h> #include<string> #include<map&

HDU 6096 String (AC自动机)

题意:给出n个字符串和q个询问,每次询问给出两个串 p 和 s .要求统计所有字符串中前缀为 p 且后缀为 s (不可重叠)的字符串的数量. 析:真是觉得没有思路啊,看了官方题解,真是好复杂. 假设原始的字符串 数组为A,首先将A中的每个字符串都进行翻转,得到字符串数组B,然后,将A和B按字典序排序. 对于一个查询来说有一个前缀p和后缀s, 所有包含前缀p的字符串在A中是连续的,可通过二分求出该区间 设为[Lp,Rp],同样,所有包含后缀s的字符串在B中也是连续的,设为[Ls,Rs] 接下来只需

2017多校第6场 HDU 6096 String AC自动机

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6096 题意:给了一些模式串,然后再给出一些文本串的不想交的前后缀,问文本串在模式串的出现次数. 解法: 因为要求前缀后缀都包含的个数,所以可以把字符串a转换成a#a这样一个字符串,比如abca就转换成abca#abca 然后对于一组前缀a后缀b转换成b{a,比如ab ca,就是ca{ab, 然后对前缀后缀的串建立AC自动机,让主串去匹配,如上述例子,ca{ab满足为abca{abca的一个子串,也就

HDU - 6086 Rikka with String AC自动机 + dp

HDU - 6086 前缀和后缀分别建AC自动机, 考虑从两端往中间dp dp[ o ][ i ][ j ][ mask ] 表示放了前面和后面o个, 第一个自动机在 i 位置, 第二个自动机在 j 位置, 拥有的目标串的状态是mask的方案数. 对于跨过两端的东西, 我们最后处理就好了. #include<bits/stdc++.h> #define LL long long #define LD long double #define ull unsigned long long #def

ZOJ3228 Searching the String(AC自动机)

题目大概是给一个主串,询问若干个模式串出现次数,其中有些模式串要求不能重叠. 对于可以重叠的就是一个直白的多模式匹配问题:而不可重叠,在匹配过程中贪心地记录当前匹配的主串位置,然后每当出现一个新匹配根据记录的位置判断这个新匹配是否成立,最后更新位置. 另外,考虑到数据可以出现多个模式串相同的情况,实现要做一些处理: 1 #include<cstdio> 2 #include<cstring> 3 #include<queue> 4 #include<algorit

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

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 string. And one day, moondy gave jay another problem, poor jay finally broke out a

AC自动机

AC自动机 直接学AC自动机比较难理解,强烈建议先学完KMP和字典树并进行一定的练习后,对于失配指针和字典树构造有一定理解后再来学AC自动机的内容.有关AC自动机的详细介绍可见刘汝佳的<算法竞赛入门经典训练指南>P214. 给你一个字典(包含n个不重复的单词),然后给你一串连续的字符串文本(长为len),问你该文本里面的哪些位置正好出现了字典中的某一个或某几个单词?输出这些位置以及出现的单词. 这个问题可以用n个单词的n次KMP算法来做(效率为O(n*len*单词平均长度)),也可以用1个字典