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

注意每个串只能成为一个串的子串 only once
【HDU 2846 ac自动机 给定n个串 q个询问 问是n个串中几个串的子串】所以用set去重



#include #include #include #include #include #include #include #include using namespace std; #define ll __int64 #define N 10010 #define inf 100000000000000 #define maxnode 250001 #define sigma_size 26struct 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 q; for(int i = 0; imyset; 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; }




    推荐阅读