题目:
1 5 6 orz sto kirigiri danganronpa ooooo o kyouko dangan ronpa ooooo ooooo
1 1 0 3 7
题意:字符串匹配,多个模式串匹配源串。
思路:AC自动机模板题。
代码:
//AC 自动机
#include <stdio.h>
#include <string.h>
#include <queue>
using namespace std;
inline int Max(int a,int b)
{
    return a>b?a:b;
}
inline int Min(int a,int b)
{
    return a>b?b:a;
}
#define maxnode 600010
#define sigma_size 26
struct Trie
{
    int ch[maxnode][sigma_size];//下一指针
    int val[maxnode];//匹配进度
    int haha[maxnode];//节点i的成功匹配数
    int f[maxnode];//失配指针
    int sz;//size
	//初始化
    void init()
    {
        sz=1;
        memset(ch,0,sizeof(ch));
        memset(val, 0, sizeof(val));
        memset(f,0,sizeof(f));
        memset(haha,0,sizeof(haha));
    }
	//字符 c 的 index
    int idx(char c)
    {
        return c-'a';
    }
	//插入串 s
    int insert(char *s)
    {
		//
        int u = 0, len = strlen(s);
        for(int i = 0; i < len; i++)
        {
			//获取index
            int c = idx(s[i]);
            if(!ch[u][c]) ch[u][c] = sz++;//无路则建立指针到最后一个节点
            u = ch[u][c];//到下一节点
        }
        val[u] ++; //将串结束的位置的val++
        return u;  //返回串S 结束位置的指针
    }
	//计算失败指针
    void getFail()
    {
        queue<int> q;
        for(int i = 0; i<sigma_size; i++)
            if(ch[0][i]) q.push(ch[0][i]);//处理根节点
		//将根节点的所有下一节点加入队列
        while(!q.empty())
        {
            int r = q.front();
            q.pop();
			//取队首为r
			//遍历r的所有下级
            for(int c = 0; c<sigma_size; c++)
            {
                int u = ch[r][c];
                if(!u)continue;//如果下一节点是根节点,跳过
				//将r的下级加入队列
                q.push(u);
                int v = f[r];
                ///沿失配边走上去 如果失配后有节点 且 其子节点c存在则结束循环
				while(v && ch[v][c] == 0) v = f[v];
				f[u] = ch[v][c];//改变失配指针
            }
        }
    }
	//匹配 串T
    void find(char *T)
    {
        int len = strlen(T), j = 0;//j为当前节点编号(0代表根节点)
        for(int i = 0; i < len; i++)
        {
            int c = idx(T[i]);
            while(j && ch[j][c]==0) //当j不是根节点且j到c无路(失配)
				j = f[j];//走失配指针到下一节点(回滚)
			//循环结束时:
			//j 为根节点 或 j到c有路(可配)
            j = ch[j][c];//j到下一节点,若j为根节点且没有路,则j还会走到根节点
            int temp = j;
			//标记整个路上的
            while(temp)//当temp不是根
            {
                haha[temp]++;//在temp节点的进度+1
                temp = f[temp];//回退到失败后节点
            }
        }
    }
};
Trie ac;
char P[100011][10010];
int ans[100010];
char S1[100010];
int main()
{
    int t,m,n;
    scanf("%d",&t);
    while(t--)
    {
        ac.init();
        scanf("%d%d",&m,&n);
        for(int i = 1; i <= m; i++)
        {
            scanf("%s",P[i]);
        }
        for(int i = 1; i <= n; i++)
        {
            scanf("%s",S1);
            ans[i] = ac.insert(S1);
        }
        ac.getFail();
        for(int i = 1; i <= m; i++)
        {
            memset(ac.haha,0,sizeof(ac.haha));
            ac.find(P[i]);
            int sum = 0;
            for(int i=1; i <= n; i++)
                sum += ac.haha[ans[i]];
            printf("%d\n",sum);
        }
    }
    return 0;
}
版权声明:本文为博主原创文章,未经博主允许不得转载。
原文地址:http://blog.csdn.net/u013840081/article/details/48070739