题目链接: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 ",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 }