做比赛的时候看这题就感觉是自动机,当时只是听说过有这个算法,但是根本没看过,晚上回去以后找教程看了一下复制了hh大神的模版,又自己敲了一下模版题,终于弄明白一点了,今天又做了一下F题这题和我做的那个模版题挺像的,不过就是多了反转以后的匹配和字符串的转换,其他的就是套模版而已。现在我也只能套模版,网上的英文教程看的云里雾里的,算了先搞个模版再说吧……
#include <cstdio>
#include <iostream>
#include <cstring>
#include <ctype.h>
using namespace std;
//MAX_NODE = StringNumber * StringLength
const int MAX_NODE = 250001;
//节点个数,一般字符形式的题26个
const int CHILD_NUM = 26;
//特定题目需要
class ACAutomaton
{
private:
int isword[MAX_NODE];
//每个节点的儿子,即当前节点的状态转移
int chd[MAX_NODE][CHILD_NUM];
//传说中的fail指针
int fail[MAX_NODE];
//队列,用于广度优先计算fail指针
int Q[MAX_NODE];
//字母对应的ID
int ID[128];
//已使用节点个数
int sz;
public:
//初始化,计算字母对应的儿子ID,如:'a'->0 ... 'z'->25
void Initialize()
{
fail[0] = 0;
for (int i = 0 ; i < CHILD_NUM ; i ++)
{
ID[i+'A'] = i;//当前匹配的字符集,根据题意进行修改,一开始没注意是大写字母,一直不对……
}
}
//重新建树需先Reset
void Reset()
{
memset(chd[0] , 0 , sizeof(chd[0]));
memset(isword,-1,sizeof(isword));
sz = 1;
}
//将权值为key的字符串a插入到trie中
void Insert(char *a)
{
int p = 0;
for ( ; *a ; a ++)
{
int c = ID[*a];
if (!chd[p][c])
{
memset(chd[sz] , 0 , sizeof(chd[sz]));
chd[p][c] = sz ++;
}
p = chd[p][c];
}
isword[p]=1;
}
//建立AC自动机,确定每个节点的权值以及状态转移
void Construct()
{
int *s = Q , *e = Q;
for (int i = 0 ; i < CHILD_NUM ; i ++)
{
if (chd[0][i])
{
fail[ chd[0][i] ] = 0;
*e ++ = chd[0][i];
}
}
while (s != e)
{
int u = *s++;
for (int i = 0 ; i < CHILD_NUM ; i ++)
{
int &v = chd[u][i];
if (v)
{
*e ++ = v;
fail[v] = chd[ fail[u] ][i];
}
else
{
v = chd[ fail[u] ][i];
}
}
}
}
int work(char *a)
{
int ret = 0 , p = 0;
for(int c = ID[*a] ; *a ; ++ a , c = ID[*a])
{
p = chd[p][c];
int pp = p;
while(pp && isword[pp] != -1)
{
ret += isword[pp];
isword[pp] = -1;
pp = fail[pp];
}
}
return ret;
}
} AC;
void transform(char s1[],char s2[])
{
int len=strlen(s1);
int p=0;
for(int i=0; i<len; i++)
{
if(s1[i]=='[')
{
i++;
int temp=0;
for(; isdigit(s1[i]); i++)
{
temp=temp*10+s1[i]-'0';
}
for(int j=0; j<temp; j++)
s2[p++]=s1[i];
i++;
}
else s2[p++]=s1[i];
}
s2[p]='\0';
}
char temp[5100005],convert[5100005],str[5100005];
char change[5100005];
int main()
{
//freopen("input.txt","r",stdin);
AC.Initialize();
int t;
scanf("%d",&t);
while(t--)
{
AC.Reset();
int n;
scanf("%d",&n);
for(int k=0; k<n; k++)
{
scanf("%s",temp);
transform(temp,convert);
AC.Insert(convert);
}
AC.Construct();
scanf("%s",str);
int len=strlen(str);
transform(str,change);
int ans=AC.work(change);
len=strlen(change);
for(int i=0,j=len-1; i<j; i++,j--)
{
swap(change[i],change[j]);
}
ans+=AC.work(change);
printf("%d\n",ans);
}
return 0;
}