【题目链接】 http://acm.hdu.edu.cn/showproblem.php?pid=6096
【题目大意】
给出一些字符串,给出前缀后缀模式询问,问有多少字符串符合该模式
【题解】
我们将字符串变为双倍,在中间增加拼接符,
对于每个前后缀模式,我们将其处理为[后缀+拼接符+前缀]的形式,
那么原题等价于统计前后缀模式在多少个字符串中出现,
我们用所有的前后缀模式建立AC自动机,用每个字符串在AC自动机上跑匹配,
最后统计fail链前继累加和即可。
【代码】
#include <cstdio> #include <cstring> using namespace std; const int N=1200010; namespace AC_DFA{ const int Csize=27; int tot,son[N][Csize],sum[N],fail[N],q[N],ans[N],dph[N],match[N]; void Initialize(){ memset(sum,0,sizeof(int)*(tot+1)); memset(dph,0,sizeof(int)*(tot+1)); memset(ans,0,sizeof(int)*(tot+1)); memset(match,0,sizeof(int)*(tot+1)); memset(fail,0,sizeof(int)*(tot+1)); for(int i=0;i<=tot;i++)for(int j=0;j<Csize;j++)son[i][j]=0; tot=0; fail[0]=-1; } inline int Tr(char ch){return ch-‘a‘;} int Insert(char *s){ int x=0; for(int l=strlen(s),i=0,w;i<l;i++){ if(!son[x][w=Tr(s[i])]){ son[x][w]=++tot; dph[tot]=i+1; }x=son[x][w]; }sum[x]++; return x; } void MakeFail(){ int h=1,t=0,i,j,x; for(i=0;i<Csize;i++)if(son[0][i])q[++t]=son[0][i]; while(h<=t)for(x=q[h++],i=0;i<Csize;i++) if(son[x][i]){ fail[son[x][i]]=son[fail[x]][i],q[++t]=son[x][i]; match[son[x][i]]=sum[son[x][i]]?son[x][i]:match[fail[son[x][i]]]; }else son[x][i]=son[fail[x]][i]; } void Search(char *s,int len){ for(int l=strlen(s),i=0,x=0,w;i<l;i++){ x=son[x][Tr(s[i])]; while(dph[x]>len)x=fail[x]; ans[match[x]]++; } } int d[N],st[N]; void Solve(){ int k=0; memset(d,0,sizeof(int)*(tot+1)); for(int i=1;i<=tot;i++)d[fail[i]]++; for(int i=1;i<=tot;i++)if(!d[i])st[k++]=i; for(int i=0;i<k;i++){ int j=fail[st[i]]; ans[j]+=ans[st[i]]; if(!--d[j])st[k++]=j; } } } int len[100010],pos[100010]; char ss[N],t1[N],t2[N]; char *s[100010]; using namespace AC_DFA; int main(){ int T,n,q; scanf("%d",&T); while(T--){ Initialize(); scanf("%d%d",&n,&q); for(int i=0,j=0;i<n;i++){ s[i]=ss+j; scanf("%s",s[i]); len[i]=strlen(s[i])+1; j+=len[i]; strcpy(ss+j,s[i]); ss[j-1]=‘z‘+1; j+=len[i]; } for(int i=0;i<q;i++){ t1[0]=‘z‘+1; scanf("%s%s",t1+1,t2); strcat(t2,t1); pos[i]=Insert(t2); }MakeFail(); for(int i=0;i<n;i++)Search(s[i],len[i]); Solve(); for(int i=0;i<q;i++)printf("%d\n",ans[pos[i]]); }return 0; }
时间: 2024-10-04 10:25:24