[AC自动机] zoj Searching the String

题意:

给一个原串,再给n个串,每个串有属性,属性0代表可以重叠,1代表不可以重叠

问每个串出现了多少次

思路:

为了方便建立两个自动机(0的一个,1的一个)

然后可以重叠的很好做,以前都做过

不可重叠的话需要记录两个东西

len[i]代表每个串的长度,used[i]代表每个串在之前出现的位置,初始化-1

然后遍历到的时候对于当前位置 j, 必须j>=used[i]+len[i] 才能算出现,并且更新

需要注意的是:

会出现同样属性并且相同的串。我处理的方式就是排序,按id排序大的在前

然后算一遍大的,用大的赋值给id 小的且串相同的。

代码:

#include"cstdlib"
#include"cstdio"
#include"cstring"
#include"cmath"
#include"queue"
#include"algorithm"
#include"iostream"
using namespace std;
char fuck[123456];
int ans[123456],used[123456],len[123456];
struct word
{
    int x,id;
    char y[7];
} dc[123456];
struct trie
{
    int mark;
    trie *next[27];
    trie *fail;
    trie()
    {
        mark=0;
        memset(next,0,sizeof(next));
        fail=NULL;
    }
};
trie *root0,*root1;
void init(int key,char *v,int id)
{
    trie *p;
    if(key) p=root1;
    else p=root0;
    for(int i=0; v[i]; i++)
    {
        int tep=v[i]-'a';
        if(p->next[tep]==NULL) p->next[tep]=new trie();
        p=p->next[tep];
    }
    p->mark=id;
}
void del(trie *p)
{
    for(int j=0; j<26; j++) if(p->next[j]!=NULL) del(p->next[j]);
    free(p);
}
void getac()
{
    queue<trie*>q;
    q.push(root0);
    while(!q.empty())
    {
        trie *p,*tep;
        p=q.front();
        q.pop();
        for(int i=0; i<26; i++)
        {
            if(p->next[i]!=NULL)
            {
                if(p==root0) p->next[i]->fail=root0;
                else
                {
                    tep=p->fail;
                    while(tep!=NULL)
                    {
                        if(tep->next[i]!=NULL)
                        {
                            p->next[i]->fail=tep->next[i];
                            break;
                        }
                        tep=tep->fail;
                    }
                    if(tep==NULL) p->next[i]->fail=root0;
                }
                q.push(p->next[i]);
            }
        }
    }
    q.push(root1);
    while(!q.empty())
    {
        trie *p,*tep;
        p=q.front();
        q.pop();
        for(int i=0; i<26; i++)
        {
            if(p->next[i]!=NULL)
            {
                if(p==root1) p->next[i]->fail=root1;
                else
                {
                    tep=p->fail;
                    while(tep!=NULL)
                    {
                        if(tep->next[i]!=NULL)
                        {
                            p->next[i]->fail=tep->next[i];
                            break;
                        }
                        tep=tep->fail;
                    }
                    if(tep==NULL) p->next[i]->fail=root1;
                }
                q.push(p->next[i]);
            }
        }
    }
}
void finde(char *v)
{
    trie *p0=root0,*p1=root1;
    for(int i=0; v[i]; i++)
    {
        int tep=v[i]-'a';
        while(p0->next[tep]==NULL && p0!=root0)
            p0=p0->fail;
        p0=p0->next[tep];
        if(p0==NULL) p0=root0;
        trie *q0=p0;
        while(q0!=root0)
        {
            if(q0->mark!=0) ans[q0->mark]++;
            q0=q0->fail;
        }
        while(p1->next[tep]==NULL && p1!=root1)
            p1=p1->fail;
        p1=p1->next[tep];
        if(p1==NULL) p1=root1;
        trie *q1=p1;
        while(q1!=root1)
        {
            if(q1->mark!=0)
            {
                if(i>=used[q1->mark]+len[q1->mark])  //不可重叠的判断
                {
                    ans[q1->mark]++;
                    used[q1->mark]=i;
                }
            }
            q1=q1->fail;
        }
    }
}
int cmp(word a,word b)  //排序的cmp
{
    if(a.x==b.x)
    {
        if(strcmp(a.y,b.y)==0)
        {
            if(a.id>b.id) return 1;
            else return 0;
        }
        else
        {
            if(strcmp(a.y,b.y)>0) return 1;
            else return 0;
        }
    }
    else
    {
        if(a.x>b.x) return 1;
        else return 0;
    }
}
int main()
{
    int cas=1;
    while(scanf("%s",fuck)!=-1)
    {
        int n;
        scanf("%d",&n);
        root0=new trie();
        root1=new trie();
        for(int i=1; i<=n; i++)
        {
            int x;
            char y[12];
            scanf("%d%s",&x,y);
            len[i]=strlen(y);
            init(x,y,i);
            dc[i].x=x;
            strcpy(dc[i].y,y);
            dc[i].id=i;
        }
        memset(ans,0,sizeof(ans));
        memset(used,-1,sizeof(used));
        getac();
        finde(fuck);
        sort(dc+1,dc+1+n,cmp);
        int i;
        for(i=1; dc[i+1].x==1; i++)  //赋值给那些重复的
        {
            if(strcmp(dc[i].y,dc[i+1].y)==0)
                ans[dc[i+1].id]=ans[dc[i].id];
        }
        for(i=i+1; i<n; i++)
        {
            if(strcmp(dc[i].y,dc[i+1].y)==0)
                ans[dc[i+1].id]=ans[dc[i].id];
        }
        printf("Case %d\n",cas++);
        for(int i=1; i<=n; i++) printf("%d\n",ans[i]);
        del(root0);
        del(root1);
        puts("");
    }
    return 0;
}
时间: 2024-10-10 20:09:00

[AC自动机] zoj Searching the String的相关文章

[AC自己主动机] zoj Searching the String

意甲冠军: 到原始字符串.给n字符串,每个字符串都有一个属性,属性0代表重叠,1代表不能重叠 请各多少次出现的字符串 思维: 为了便于建立两台机器自己主动(0一个.1一个) 然后,它可以重叠非常好做,谁做 不可重叠的话须要记录两个东西 len[i]代表每一个串的长度,used[i]代表每一个串在之前出现的位置,初始化-1 然后遍历到的时候对于当前位置 j. 必须j>=used[i]+len[i] 才干算出现.而且更新 须要注意的是: 会出现相同属性而且相同的串. 我处理的方式就是排序.按id排序

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

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

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

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

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

ZOJ 2619 Generator (概率、AC自动机、高斯消元)

Generator 题目:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=2619 题意:给定一个数N,代表可以选前N个字母.然后给定一个仅有前N个字母组成的字符串,问从空串开始构造,每次可以在已有基础上从前N个字母中挑选一个加在后面,问构造的字符串的长度期望是多少? 思路:如果给定的串长度为L,那么对于构造的串,对应的状态就是0到L之间的数.如果为L即为构造成功.记F[i] 为从i状态到达L状态期望的步数,那么对于0到L

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