题意:给你两种串,一种可以当前缀,一种可以当后缀,问两种串合起来,一共有多少种组合。并且没有重合。
思路:我们先将两种串插入字典树,对于后缀串,我们反向插入,然后处理出每个字符对应的后缀的个数。
我们来看一个组合的串,c = a + b 。这个c可能很多种组合,但是,只要我们取a最大,那么这样计数就是唯一的。所谓a最大就是当搜到a是该前缀的最后一个字母,那么a就是最大的。
这是对应a是最后一个字母的情况,那么如果a后面还有字母呢,那么我们可以找是否存在一个后缀,他只有一个字母,那么我们可以把他接到a的后面。
所以对应的一个前缀a,我们只要分这两种情况考虑即可。
注意是使用long long 。
#define N 311111 ll ans = 0 ; ll sum[30] ; int end[30] ; struct TT { int num ; int T[N][26] ; TT() { num = 0 ; } void INIT() { mem(T[0], -1) ; num = 0 ; } void init(int x) { mem(T[x] , -1) ; } void insert(char *s) { int l = strlen(s) ; int now = 0 ; for (int i = 0 ; i < l ; i ++ ) { int a = s[i] - 'a' ; if(T[now][a] == -1) { T[now][a] = ++ num ; init(num) ; } now = T[now][a] ; } } void cal(int now) { for (int i = 0 ; i < 26 ; i ++ ) { if(T[now][i] == -1) { ans += sum[i] ; } else { if(end[i]) ans ++ ; cal(T[now][i]) ; } } } int fk(int now) { for (int i = 0 ; i < 26 ; i ++ ) { if(T[now][i] != -1) { sum[i] ++ ; fk(T[now][i]) ; } } } } sufTree , preTree ; char s[1111] , p[1111] ; int P , S ; int main() { while(cin >> P >> S, (P + S)) { sufTree.INIT() ; preTree.INIT() ; for (int i = 0 ; i < P ; i ++ ) { scanf("%s",p) ; preTree.insert(p) ; } for (int i = 0 ; i < S ; i ++ ) { scanf("%s",s) ;int l = strlen(s) ; reverse(s , s + l) ; sufTree.insert(s) ; } mem(sum , 0) ; mem(end , 0) ; ans = 0 ; sufTree.fk(0) ; for (int i = 0 ; i < 26 ; i ++ )if(sufTree.T[0][i] != -1)end[i] = 1 ; for (int i = 0 ; i < 26 ; i ++ )if(preTree.T[0][i] != -1)preTree.cal(preTree.T[0][i]) ; printf("%lld\n",ans) ; } return 0 ; }