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>
#include<vector>
#include <algorithm>
#include <queue>
#include <cmath>

#define LL long long
#define ULL unsigned long long

using namespace std;

const int MAXS = 26,MAXN  = 600010;
const int MATN = 70;

struct MAT
{
    int row,col;
    ULL mat[MATN][MATN];

    void Init(int R,int C,int val)
    {
        row = R,col = C;

        for(int i = 1;i <= row; ++i)
            for(int j = 1;j <= col; ++j)
                    mat[i][j] = (i == j ? val : 0);
    }

    MAT Multi(MAT c,LL MOD)
    {
        MAT tmp;
        tmp.Init(this->row,c.col,0);

        int i,j,k;
       for(k = 1;k <= this->col; ++k)
            for(i = 1;i <= tmp.row; ++i)
                for(j = 1;j <= tmp.col; ++j)
                    tmp.mat[i][j] += (this->mat[i][k]*c.mat[k][j]);

        return tmp;
    }

    MAT Quick(LL n,LL MOD)
    {
        MAT res,tmp = *this;

        res.Init(row,col,1);

        while(n)
        {
            if(n&1)
                res = res.Multi(tmp,MOD);
            tmp = tmp.Multi(tmp,MOD);
            n >>= 1;
        }

        return res;
    }

    void Output()
    {
        cout<<"         ****************        "<<endl;
        int i,j;
        for(i = 1;i <= row; ++i)
        {
            for(j = 1;j <= col; ++j)
                    printf("%3lld ",mat[i][j]);
            puts("");
        }
        cout<<"         &&&&&&&&&&&&&       "<<endl;
    }

};

struct Trie
{
    int next[MAXS];
    int fail;
    int flag;
} st[MAXN];

queue<int> q;

int anw[100010];

int pre[100010];

struct QUERY
{
    int y;
    char s[8];
    int len;
}que[100100];

struct ACautomaton
{
    int Top,root;

    int  Creat()
    {
        memset(st[Top].next,-1,sizeof(st[Top].next));
        st[Top].flag = 0;
        st[Top].fail = -1;
        return Top++;
    }

    void Init()
    {
        Top = 0;
        root = Creat();
    }

    inline int CalIndex(int c)
    {
        return c-'a';
    }

    void Insert(char *s,int ty)
    {
        int i = 0,tr = root,tmp;

        while(s[i] != '\0')
        {
            tmp = CalIndex(s[i]);
            if(st[tr].next[tmp] == -1)
                st[tr].next[tmp] = Creat();
            tr = st[tr].next[tmp],++i;
        }
        st[tr].flag = ty;
    }

    void GetFail()
    {
        st[root].fail = -1;
        q.push(root);

        int f,t;

        while(q.empty() == false)
        {
            f = q.front();
            q.pop();

            for(int i = 0; i < MAXS; ++i)
            {
                if(st[f].next[i] != -1)
                {
                    t = st[f].fail;

                    while(t != -1 &&  st[t].next[i] == -1)
                        t = st[t].fail;

                    if(t == -1)
                        st[st[f].next[i]].fail = root;
                    else
                        st[st[f].next[i]].fail = st[t].next[i];

                    q.push(st[f].next[i]);
                }
            }
        }
    }

    int OverLapMatch(char *s)
    {
        int i ,tr = root,tmp;
        int ans = 0;
        for(i = 0; s[i] != '\0'; ++i)
        {
            tmp = CalIndex(s[i]);

            while(tr != -1 && st[tr].next[tmp] == -1 )
                tr = st[tr].fail;
            if(tr == -1)
            {
                tr = root;
                continue;
            }

            tr = st[tr].next[tmp];

            tmp = tr;

            while(tmp != root && st[tmp].flag != -1)
            {
                if(st[tmp].flag)
                    ans++,anw[st[tmp].flag]++;
                tmp = st[tmp].fail;
            }
        }
        return ans;
    }

    int NoOverLapMatch(char *s)
    {
        int i ,tr = root,tmp;
        int ans = 0;
        for(i = 0; s[i] != '\0'; ++i)
        {
            tmp = CalIndex(s[i]);

            while(tr != -1 && st[tr].next[tmp] == -1 )
                tr = st[tr].fail;

            if(tr == -1)
            {
                tr = root;
                continue;
            }

            tr = st[tr].next[tmp];

            tmp = tr;

            while(tmp != root && st[tmp].flag != -1)
            {
                if(st[tmp].flag)
                {
                    if(i-pre[st[tmp].flag] >= que[st[tmp].flag].len)
                    ans++,anw[st[tmp].flag]++,pre[st[tmp].flag] = i;
                }
                tmp = st[tmp].fail;
            }
        }
        return ans;
    }
};

char s[100010];

map<string,int> M;
map<string,int>::iterator it;

int main()
{
   // freopen("data1.in","r",stdin);
    int n,i;
    ACautomaton AC;

    int icase =1;

    while(scanf("%s",s) != EOF)
    {
        scanf("%d",&n);

        for(i = 1;i <= n; ++i)
            scanf("%d %s",&que[i].y,que[i].s);

        for(i = 1;i <= n; ++i)
            que[i].len = strlen(que[i].s);

        memset(pre,-1,sizeof(pre));
        memset(anw,0,sizeof(anw));

        AC.Init();

        for(i = 1;i <= n; ++i)
        {
            if(que[i].y == 0)
                AC.Insert(que[i].s,i);
        }

        AC.GetFail();

        AC.OverLapMatch(s);

        M.clear();

        for(i = n;i >= 1; --i)
        {
            if(que[i].y == 0)
            {
                it = M.find(que[i].s);

                if(it != M.end())
                    anw[i] = anw[it->second];
                else
                    M.insert(pair<string,int>(que[i].s,i));
            }
        }

        AC.Init();

        for(i = 1;i <= n; ++i)
        {
            if(que[i].y == 1)
                AC.Insert(que[i].s,i);
        }

        AC.GetFail();

        AC.NoOverLapMatch(s);

        M.clear();

        for(i = n;i >= 1; --i)
        {
            if(que[i].y == 1)
            {
                it = M.find(que[i].s);

                if(it != M.end())
                    anw[i] = anw[it->second];
                else
                    M.insert(pair<string,int>(que[i].s,i));
            }
        }
        printf("Case %d\n",icase++);
        for(i = 1;i <= n; ++i)
            printf("%d\n",anw[i]);
        puts("");
    }

    return 0;
}
时间: 2024-08-02 19:41:55

ZOJ 3228 Searching the String AC自动机的不重复匹配的相关文章

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自己主动机)

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自己主动机)

题目链接: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

题目:给你一个长目标串str,和一些模式串,求每个串出现的次数.模式串有可覆盖和不可覆盖两种. 分析:字符串,多串匹配,AC自动机.由于数据有可能不允许相交,所以记录上一个的结束位置. 题目的数据比较猥琐,可能相同,采用一个 Fath域记录第一次出现的 id,计算一次就可以了. 说明:注意数据有相同的串:该题可以使用 RK算法+二分. #include <stdio.h> #include <stdlib.h> #include <string.h> char Word

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自动机)

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

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