zoj 3228 - Searching the String

题目:给你一个长目标串str,和一些模式串,求每个串出现的次数。模式串有可覆盖和不可覆盖两种。

分析:字符串,多串匹配,AC自动机。由于数据有可能不允许相交,所以记录上一个的结束位置。

题目的数据比较猥琐,可能相同,采用一个 Fath域记录第一次出现的 id,计算一次就可以了。

说明:注意数据有相同的串;该题可以使用 RK算法+二分。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char Word[10];
char Line[100005];
int  Walk[100005];
int  Fath[100005];

/* AC_DFA define */
#define nodesize 300005
#define dictsize 26

typedef struct node
{
    int   flag[2];
    int   last;
    int   deep;
    node* fail;
    node* next[dictsize];
}tnode;
tnode  dict[nodesize];
tnode* Q[nodesize];
int    ID[256];

class AC_DFA
{
    private:
        int    size;
        tnode* root;
    public:
        AC_DFA() {makeID();init();}
        void makeID() {
            for (int i = 0 ; i < dictsize ; ++ i)
                ID[i+'a'] = i;
        }
        void init() {
            memset(dict, 0, sizeof(dict));
            root=NULL;size=0;root=newnode();
        }
        tnode* newnode() {
            dict[size].fail = root;
            dict[size].last = -1;
            return &dict[size ++];
        }
        void insert(char* word, int id, int s) {
            tnode* now = root;
            for (int i = 0 ; word[i] ; ++ i) {
                if (!now->next[ID[word[i]]])
                    now->next[ID[word[i]]] = newnode();
                now = now->next[ID[word[i]]];
            }
            /* 记录数据,相同的计入父节点 */
			if (!now->flag[s]) {
				now->deep = strlen(word);
				now->flag[s] = id;
			}else Fath[id] = now->flag[s];
        }
        void setfail() {
            Q[0] = root; root->fail = NULL;
            for (int move = 0,save = 1 ; move < save ; ++ move) {
                tnode* now = Q[move];
                for (int i = 0 ; i < dictsize ; ++ i)
                    if (now->next[i]) {
                        tnode* p = now->fail;
                        while (p && !p->next[i]) p = p->fail;
                        now->next[i]->fail = p?p->next[i]:root;
                        Q[save ++] = now->next[i];
                    }else now->next[i] = now==root?root:now->fail->next[i];//构建 Trie图
            }
        }
        int query(char* line, int N) {
        	memset(Walk, 0, sizeof(Walk));
            tnode* now = root;
            for (int i = 0 ; line[i] ; ++ i) {
                now = now->next[ID[line[i]]];
                for (tnode* p = now ; p ; p = p->fail) {
                	if (p->flag[0]) ++ Walk[p->flag[0]];
                    if (p->flag[1] && p->last+p->deep <= i) {
                        p->last = i;
                        ++ Walk[p->flag[1]];
                    }
				}
            }
            for (int i = 1 ; i <= N ; ++ i)
                printf("%d\n",Walk[Fath[i]]);
            return 0;
        }
};
/* AC_DFA  end */
int main()
{
    int N,S,T = 1;
    AC_DFA ac;
    while (scanf("%s",Line) != EOF) {
        ac.init();
        scanf("%d",&N);
        for (int i = 1 ; i <= N ; ++ i) {
            scanf("%d %s",&S,Word);
            Fath[i] = i;
            ac.insert(Word, i, S);
        }
        ac.setfail();
        printf("Case %d\n",T ++);
        ac.query(Line, N);
        printf("\n");
    }
    return 0;
}
时间: 2024-11-07 14:13:14

zoj 3228 - Searching the String的相关文章

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

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

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&

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

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

ZOJ 3587 Marlon&#39;s String 扩展KMP

链接:http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemCode=3587 题意:给出两个字符串S和T,S,T<=100000.拿出S的两个子串(可以重叠),将两个子串连接起来成为字符串T的方法有多少种. 思路:用扩展KMP求出S的从每位开始的子串与T的公共前缀,再将两个子串翻转,再用扩展KMP求出S反的从每位开始的子串与T反的公共前缀.找出其中和为T子串长度的S公共前缀和S反的公共前缀的数量,相乘为结果. 代码: #include

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

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

题目大意:首先给你一下母串,长度不超过10^5,然后有 N(10^5) 次查询,每次查询有两种命令,0或者1,然后加一个子串,询问母串里面有多少个子串,0表示可以重复,1表示不可以重复.   分析:发现查询的次数是比较多的,然后可以利用查询的串建立一个trie,然后用母串跑一遍就行了,不过有两种操作比较麻烦一些,不过我们可以保存查询时每个节点的查询结果,然后每个串都对应一个节点,最后输出查询结果即可,这样也可以规避掉重复串的问题.   代码如下: ========================