题目链接:点击打开链接
题意:
case数
n个模式串
一个母串。
问:n个模式串出现的种数(一个模式串多次出现只算一次)
对于 "ABC" , 若母串出现了"CBA"这样的反串,也算出现了。
所以:
1
ABC
CBA
ans = 1
#include <cstdio> #include <cstring> #include <cmath> #include <queue> #include <algorithm> using namespace std; const int maxnode = 250*1000+10000; const int 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 road[maxnode]; //路径压缩优化 针对计算模式串出现的种数 int sz; int Newnode() { val[sz] = f[sz] = last[sz] = len[sz] = num[sz] = 0; memset(ch[sz], 0, sizeof ch[sz]); return sz++; } void init(){ sz=0; Newnode(); } int idx(char c){ return c-'A'; } int insert(char *s){ int u = 0; for(int i = 0, c; s[i] ;i++){ c = idx(s[i]); if(!ch[u][c]) ch[u][c] = Newnode(); pre[ch[u][c]] = u; Char[ch[u][c]] = s[i]; len[ch[u][c]] = len[u]+1; road[ch[u][c]] = 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]); int r, c, u, v; while(!q.empty()){ r = q.front(); q.pop(); for(c = 0; c<sigma_size; c++){ u = ch[r][c]; if(!u)continue; q.push(u); v = f[r]; while(v && ch[v][c] == 0) v = f[v]; //沿失配边走上去 如果失配后有节点 且 其子节点c存在则结束循环 f[u] = ch[v][c]; } } } void find(char *T){ //计算模式串出现的个数:(每种多次出现算多次) int j = 0; for(int i = 0, c, temp; T[i] ; i++){ c = idx(T[i]); while(j && ch[j][c]==0) j = f[j]; j = ch[j][c]; temp = j; while(temp){ num[temp]++; temp = f[temp]; } } } void find_kind(char *T, int &ans){ //计算种数, 重复出现的不再计算(若多个询问则要在此处加for(i=0->sz)lu[i]=1; int j = 0, i, c, temp; for(i = 0; T[i]; i++){ c = idx(T[i]); while(j && ch[j][c] == 0) j = f[j]; j = ch[j][c]; temp = j; while(temp && road[temp]){ if(val[temp]) { ++ans; val[temp] = 0; } road[temp] = 0; temp = f[temp]; } } } }ac; char s[1015], a[5100010], b[5100010], c; int n, num; int main() { int T; scanf("%d", &T); while (T-->0) { ac.init(); scanf("%d", &n); while(n--){ scanf("%s", s); ac.insert(s); } ac.getFail(); int top = 0; scanf("%s", a); int i = 0; while(a[i]){ if(a[i]!='[') b[top++] = a[i]; else { num = 0; i++; while( '0' <= a[i] && a[i] <= '9') num = num*10 + a[i]-'0', i++; c = a[i]; i++; while(num-- > 0){ b[top++] = c; } } i++; } a[top] = b[top] = 0; for(int i = top-1; i >= 0; i--)a[i] = b[top-i-1]; int ans = 0; ac.find_kind(b, ans); ac.find_kind(a, ans); printf("%d\n", ans); } return 0; }
时间: 2024-10-05 14:27:18