2018/2/22 每日一学 AC自动机

AC自动机=trie树+KMP。

代码如下:(自行理解)

#include<cstdio>
#include<string.h>
#include<math.h>
#include<queue>
#include<algorithm>
#define N 500006
using namespace std;

char st[1000005];
char keyword[55];
int n,m;
int next[N][26],cnt[N],fail[N],pos;

int newnode()
{
    for(int i=0; i<26; i++) next[pos][i] = 0;
    fail[pos] = cnt[pos] = 0;
    return pos++;
}

void insert(char *s) //构造trie
{
    int i,p = 0;
    for(i=0; s[i]; i++)
    {
        int k = s[i] - ‘a‘, &x = next[p][k];
        p = x?x : x = newnode();
    }
    cnt[p]++; // 位运算要用
}

void makenext()  // 构造失败指针
{
    int i;
    queue<int>q;
    q.push(0);
    while(!q.empty())  // 这个代码为什么会这么强?
    {
        int u = q.front();
        cnt[u] += cnt[fail[u]];

        q.pop();
        for(i=0; i<26; i++)
        {
            int v = next[u][i];
            if(v == 0)
              next[u][i] = next[fail[u]][i]; // why? 缺少v, 求next
            else
              q.push(v);

            if(u && v)
            {
                fail[v]=next[fail[u]][i]; // 为什么只弄了一下? 如果没有会怎么样? 求fail
            }
        }
    }
}

int query(char *s)
{
    int ret = 0, idx, d = 0;
    for(int i=0; s[i]; i++)
    {
        idx = s[i] - ‘a‘;
        d = next[d][idx];
        ret += cnt[d];
        cnt[d] = 0;
    }
    return ret;
}

int main()
{
    int cas;
    scanf("%d",&cas);

    while(cas--)
    {
        scanf("%d",&n);
        pos = 0, newnode();
        for(int i=0; i<n; i++)
        {
            scanf("%s",keyword);
            insert(keyword);
        }

        makenext();
        scanf(" %s",st);
        printf("%d\n",query(st));
    }
}

原文地址:https://www.cnblogs.com/Alex-leaves/p/8458179.html

时间: 2024-08-28 21:32:08

2018/2/22 每日一学 AC自动机的相关文章

2018/2/10 每日一学 差分约束算法

差分约束算法 我们知道,对于一个最短路问题中的某边<u,v>,必定有d[v]<=d[u]+w,稍稍变形可得d[v]-d[u]<=w,是不是很像x1-x2<=a这种数学不等式? 所以对于一不等式组,我们可以将其转化为x1-x2<=a形式,连接一条有向边(X2->X1),权值为a,然后求最短路就行了. 注意如果对于负环的判断以及图的连通判断-- 刷点题再看看吧. 原文地址:https://www.cnblogs.com/Alex-leaves/p/8439751.ht

2018/2/11 每日一学 无向图割顶和桥

割顶和桥:对于无向图G,如果删除某个节点u后,连通分量数目增加,则称u为图的割顶:如果删除某条边后,连通分量数目增加,则称该边为图的桥. 对于连通图删除割顶或桥后都会使得图不再连通. 我们利用dfs的性质来快速找出一个连通图中的所有的割顶和桥. 设low[u]为u及其后代所能连回的最早的祖先的pre[]值,pre[]为时间戳则当u存在一个子节点v使得low[v] >= pre[u]时u就为割顶 同理当 low[v] > pre[u]时 u-v为桥 看代码吧(转自http://blog.csdn

2018/2/12 每日一学 三分搜索

对于二分,设left,right为问题的两个极值,用min=left+(right-left)>>1或mid=(left+right)>>1,可以知道mid值,判断,然后进行更换. 显然,二分适用于单调函数,而对于一个二次函数就无效了. 这时,我们可以用三分搜索来做. 我们定义midl=(left+mid)>>1,midr=(right+mid)>>1.判断midl和midr就行了. 看看代码吧:(转自http://blog.csdn.net/u011787

2018/2/16 每日一学 A*搜索

A*搜索 我们知道dfs和bfs在搜索中会搜素一些完全不会搜的点,这是因为,他们只考虑到起点到当前点的作用,未考虑到终点. 我们不妨设f[i]=g[i]+h[i],其中g[i]为到i的最短路(已知),h[i]为i到终点的估计值.所以说,我们用f[i]做bfs 每次取出f最小的i,拓展,然后直到终点-- 那么h[i]怎么求?? 我们可以用曼哈顿距离或者欧式距离等等来表示,注意我们要用二叉堆来维护f数组. 代码目前网上很多,就不写了. 原文地址:https://www.cnblogs.com/Ale

2018/2/17 每日一学 RMQ

什么是RMQ? 给予n个数,对于区间[l,r]查询最小.最大值. 这就是RMQ. 怎么做? 我们不妨设f[i][j]表示从i开始的2^j个数极值. 显然,他表示的是[i,i+2^j-1],注意有-1(想想,为什么?) 那么我们不难得到递推式:f[i][j]=min/max(f[i][j-1]+f[i+1<<(j-1)+1][j-1]. 注意先枚举j,联系以下区间dp不难明白为什么先枚举j. 最后怎么查询??? 很简单,分治的思想. 假设我们查询[x,y],则ans=max/min([x][k]

2018/2/24 每日一学 字符串最小表示法

非常简单,直接上代码: int minimalRepresentation() { int n = strlen(str); int i = 0,j = 1, k = 0; while(i<n && j<n && k<n) { int t = str[(i+k)%n] - str[(j+k)%n] ; if(t == 0) k++; else { if(t>0) i+=k+1; else j+=k+1; if(i==j) j++; k = 0; }

2018/03/07 每日一学PHP 之 常量defind 和 const区别

什么是常量? 如字面理解的,在脚本执行期间不可改变的的量. 定义一个常量应该注意的事项? 1:常量默认大小写敏感,错误的大小写不会被识别为常量. 2:常量只能是标量数据,也可以定义 资源 常量,但是定义了,会发生一些奇妙的,不可预知的错误,所以应当尽量避免. 标量数据:(boolean,integer,float 和 string) 通过 defind 和 const 区别 1:重复定义 1:defind 重复定义常量,常量不会被修改,php报一个 通知 错误: 报错: 结论: 虽不影响程序运行

2018/03/10 每日一学PHP 之 修饰符 public/private/protected

对于面向对象 修饰符的使用是我们最常用,也是很容易忽略的小细节. 对于编程来说,把握好每一个小细节,就能构造出漂亮,优雅的程序. public 使用最多的修饰符,公共方法,允许所有访问,就像一个公交车一样,上来交钱[参数],有钱就行,无所谓是谁. 对于这个修饰符救不在做更多的解释了,因为他的使用实在是太多了. PS:如果一个方法没有定义修饰符,那么在PHP5中,默认是public. private 私有方法, 不允许在直接实例化后访问,子类也不能直接访问,只允许在自己的类中使用. 道理我都懂,我

AC自动机

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