HDU 2846 ac自动机 给定n个串 q个询问 问是n个串中几个串的子串

注意每个串只能成为一个串的子串 only once

所以用set去重


#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
#include <math.h>
#include <queue>
using namespace std;
#define ll __int64
#define N 10010  
#define inf 100000000000000
#define maxnode 250001
#define sigma_size 26

struct Trie{
	int ch[maxnode][sigma_size];
	int val[maxnode];	 //该单词在模式串中出现的次数
	int last[maxnode];
	int f[maxnode];		 //失配数组
	int num[maxnode];	 //该单词出现在文本串的次数
	int pre[maxnode];    //该单词的前驱
	int len[maxnode];    //以该单词结尾的单词长度
	int Char[maxnode];	 //该单词对应的字母
	int sz;
	void init(){
		sz=1;
		memset(ch,0,sizeof(ch));
		memset(val, 0, sizeof(val));  
		memset(f,0,sizeof(f));
		memset(last,0,sizeof(last));    //记录该节点前一个节点是谁
		memset(len, 0, sizeof(len));
	}
	int idx(char c){ return c-'a'; }
	int insert(char *s){
		int u = 0;
		for(int i = 0; s[i] ;i++){
			int c = idx(s[i]);
			if(!ch[u][c])
				ch[u][c] = sz++;
			pre[ch[u][c]] = u;
			Char[ch[u][c]] = s[i];
			len[ch[u][c]] = len[u]+1;
			u = ch[u][c];
		}
		val[u] = 1;
		num[u] = 0;
		return u;
	}
   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();    
            for(int c = 0; c<sigma_size; c++){    
                int u = ch[r][c];    
                if(!u)continue;    
                q.push(u);    
                int v = f[r];    
                while(v && ch[v][c] == 0) v = f[v]; //沿失配边走上去 如果失配后有节点 且 其子节点c存在则结束循环    
                f[u] = ch[v][c];    
            }    
        }    
    }    
	void find(char *T){
		set<int>myset; myset.clear();
		int j = 0;
		for(int i = 0; T[i] ; i++){
			int c = idx(T[i]);
			while(j && ch[j][c]==0) j = f[j];
			j = ch[j][c];

			int temp = j;
			while(temp){ //沿失配边走 || 若沿失配边走时一定要节点为单词结尾则改成while(temp && val[temp])
				if(myset.find(temp)==myset.end()){
					myset.insert(temp);
				num[temp]++;
				}
				temp = f[temp];
			}
		}
	}
}ac;
int Stack[100010];
char s[30], hehe[N][30];
int main(){
	int n, que, i;
	ac.init();
	scanf("%d",&n);
	for(i = 0; i < n; i++)scanf("%s",hehe[i]);
	scanf("%d",&que);
	for(i = 0; i < que; i++){
		scanf("%s",s);
		Stack[i] = ac.insert(s);
	}
	ac.getFail();
	for(i = 0; i < n; i++)ac.find(hehe[i]);
	for(i = 0; i < que; i++)printf("%d\n",ac.num[Stack[i]]);
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值