Description
某国颁布了一本 n (n ≤ 10 000) 个单词的词典。单词长
度不超过 40。
该国的造词法是这样的:
1: 词典中的单词是一个词。
2: 能分为两部分的,其中前一部分是一个词典词或者其非
空前缀,后一部分是一个词典词或者其非空后缀的词。
求能造出的不相同的词汇数目。
将所有单词建成trie(A),反转后也建一颗trie(B),答案有三种情况
1.原有单词
2.原有单词的 长度>1的 严格前缀,且其最后一个字母是某单词的首字母
3.不是原有单词或其前缀,但可以由前缀和后缀拼出(由于可能重复,对一个由两个单词拼出的串只统计后缀最短的一个,)
分类统计即可
#include<cstdio> #include<cstring> typedef long long i64; const int N=400007; i64 ans=0; char ss[10007][43]; int n,ch[N][26],p1=1,p2=1,t0[26],t1[26],t2[26]; int*ed[N]; bool e[N],ee[26]; int main(){ scanf("%d",&n); for(int t=0;t<n;++t){ scanf("%s",ss[t]); int l=strlen(ss[t]),w=1,c; for(int i=0;i<l;++i){ c=ss[t][i]-'a'; int &u=ch[w][c]; if(!u)ed[u=++p1]=&u,++t1[c]; w=u; } ee[c]=1; if(!e[w]){ if(l>1)--t0[c]; e[w]=1; ++ans; } } for(int i=0;i<26;++i)if(ch[1][i])--t1[i]; for(int i=0;i<26;++i)if(ee[i])ans+=t0[i]+t1[i]; for(int i=2;i<=p1;++i)*ed[i]=0; for(int t=0;t<n;++t){ int l=strlen(ss[t]),w=1; for(int i=l-1;i>=0;--i){ int c=ss[t][i]-'a',&u=ch[w][c]; if(!u)u=++p2,++t2[c]; w=u; } } ans+=i64(p1-1)*(p2-1); for(int i=0;i<26;++i)ans-=i64(t1[i])*t2[i]; printf("%lld\n",ans); return 0; }