hdu 5129 Yong Zheng's Death(AC自动机fail树的应用)

题目链接:hdu 5129 Yong Zheng's Death

题意:

给你n个串,每个串串长30,现在让你构造串,使得该串能分成uv,u和v都是给出串中的前缀。

问能构造出多少这样的串。

题解:

这题主要是在如何去重。

如果不考虑重复,显然就是不同前缀串的数量的平方。

但是这里有算重,这里要求,以i节点为后缀的前缀个数。

这是一个AC自动机fail树的性质,以i节点为后缀的前缀个数等于该节点的子树大小。

然后后面做的就像这位dalao说的一样。

 1 #include<bits/stdc++.h>
 2 #define F(i,a,b) for(int i=a;i<=b;i++)
 3 using namespace std;
 4 
 5 const int AC_N=10000*51,tyn=26;
 6 struct AC_automation{
 7     int tr[AC_N][tyn],cnt[AC_N],Q[AC_N],fail[AC_N],fa[AC_N],tot;
 8     inline int getid(char x){return x-'a';}
 9     void nw(){cnt[++tot]=0,fail[tot]=0;memset(tr[tot],0,sizeof(tr[tot]));}
10     void init(){tot=-1,fail[0]=-1,nw();}
11     void insert(char *s,int x=0){
12         for(int i=0,w;s[i];x=tr[x][w],i++)
13             if(!tr[x][w=getid(s[i])])nw(),tr[x][w]=tot,fa[tot]=x;
14         cnt[x]++;//串尾标记 
15     }
16     void build(int head=1,int tail=0){
17         for(int i=0;i<tyn;i++)if(tr[0][i])Q[++tail]=tr[0][i];
18         while(head<=tail)for(int x=Q[head++],i=0;i<tyn;i++)
19             if(tr[x][i])fail[tr[x][i]]=tr[fail[x]][i],Q[++tail]=tr[x][i];
20             else tr[x][i]=tr[fail[x]][i];
21     }
22     int sum[AC_N];//以i节点为后缀的前缀个数
23     vector<int>g[AC_N];
24     
25     void dfs(int x)
26     {
27         sum[x]=1;
28         for(auto &it:g[x])
29             dfs(it),sum[x]+=sum[it];
30     }
31     void solve()
32     {
33         F(i,0,tot)g[i].clear();
34         F(i,1,tot)g[fail[i]].push_back(i);
35         dfs(0);
36         long long tmp=0;
37         F(i,1,tot)if(fail[i])
38         {
39             int p=fail[i],q=i;
40             while(p)p=fa[p],q=fa[q];
41             tmp+=sum[q]-1;
42         }
43         printf("%lld\n",1ll*tot*tot-tmp);
44     }
45 }AC;
46 
47 int n;
48 char s[50];
49 
50 int main()
51 {
52     while(scanf("%d",&n),n)
53     {
54         AC.init();
55         F(i,1,n)scanf("%s",s),AC.insert(s);
56         AC.build(),AC.solve();
57     }
58     return 0;
59 }
View Code

 

posted @ 2017-10-15 20:40  bin_gege  阅读(333)  评论(0编辑  收藏  举报