题目:给你一个长目标串str,和一些模式串,求每个串出现的次数。模式串有可覆盖和不可覆盖两种。
分析:字符串,多串匹配,AC自动机。由于数据有可能不允许相交,所以记录上一个的结束位置。
题目的数据比较猥琐,可能相同,采用一个 Fath域记录第一次出现的 id,计算一次就可以了。
说明:注意数据有相同的串;该题可以使用 RK算法+二分。
#include <stdio.h> #include <stdlib.h> #include <string.h> char Word[10]; char Line[100005]; int Walk[100005]; int Fath[100005]; /* AC_DFA define */ #define nodesize 300005 #define dictsize 26 typedef struct node { int flag[2]; int last; int deep; node* fail; node* next[dictsize]; }tnode; tnode dict[nodesize]; tnode* Q[nodesize]; int ID[256]; class AC_DFA { private: int size; tnode* root; public: AC_DFA() {makeID();init();} void makeID() { for (int i = 0 ; i < dictsize ; ++ i) ID[i+'a'] = i; } void init() { memset(dict, 0, sizeof(dict)); root=NULL;size=0;root=newnode(); } tnode* newnode() { dict[size].fail = root; dict[size].last = -1; return &dict[size ++]; } void insert(char* word, int id, int s) { tnode* now = root; for (int i = 0 ; word[i] ; ++ i) { if (!now->next[ID[word[i]]]) now->next[ID[word[i]]] = newnode(); now = now->next[ID[word[i]]]; } /* 记录数据,相同的计入父节点 */ if (!now->flag[s]) { now->deep = strlen(word); now->flag[s] = id; }else Fath[id] = now->flag[s]; } void setfail() { Q[0] = root; root->fail = NULL; for (int move = 0,save = 1 ; move < save ; ++ move) { tnode* now = Q[move]; for (int i = 0 ; i < dictsize ; ++ i) if (now->next[i]) { tnode* p = now->fail; while (p && !p->next[i]) p = p->fail; now->next[i]->fail = p?p->next[i]:root; Q[save ++] = now->next[i]; }else now->next[i] = now==root?root:now->fail->next[i];//构建 Trie图 } } int query(char* line, int N) { memset(Walk, 0, sizeof(Walk)); tnode* now = root; for (int i = 0 ; line[i] ; ++ i) { now = now->next[ID[line[i]]]; for (tnode* p = now ; p ; p = p->fail) { if (p->flag[0]) ++ Walk[p->flag[0]]; if (p->flag[1] && p->last+p->deep <= i) { p->last = i; ++ Walk[p->flag[1]]; } } } for (int i = 1 ; i <= N ; ++ i) printf("%d\n",Walk[Fath[i]]); return 0; } }; /* AC_DFA end */ int main() { int N,S,T = 1; AC_DFA ac; while (scanf("%s",Line) != EOF) { ac.init(); scanf("%d",&N); for (int i = 1 ; i <= N ; ++ i) { scanf("%d %s",&S,Word); Fath[i] = i; ac.insert(Word, i, S); } ac.setfail(); printf("Case %d\n",T ++); ac.query(Line, N); printf("\n"); } return 0; }
时间: 2024-11-07 14:13:14