转载请注明出处,谢谢http://blog.csdn.net/ACM_cxlove?viewmode=contents by---cxlove
题目:有两个字符串集合,从第一个集合中取某个串的非空前缀,从第二个集合中取某个串的非空后缀,拼接成一个串,问有多少个不同的新串。
https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3803
大概是N年前训练的题。。。然后不会做,就没管了
最近波波好同学问了御坂姐姐,然后就会做了,其实很水。。。
为何这么弱。。。。
首先把第一个集合中的串加入到Trie中,然后就可以枚举前缀了,然后就是统计后缀,麻烦的是可能出现重复的。
当我们按长度枚举前缀的时候,可以考虑如果后缀的前缀出现在前缀的后继中,那便不用考虑,后面总会统计到。
这样的话,其实只要比较第一个字母。
如果当前结点P表示一个前缀串,那么如果p -> next[i]为空,说明前缀中不含字母i为后继,那么我们就可以统计以i开头的后缀了。否则总能在p -> next[i]为前缀中统计到。
有一点需要注意的是,如果 p -> next[i]便是我们最终的串,即以p 为前缀时,后缀只有一个字母的话,那就不能把这一个字母拉入到前缀中,因为后缀是非空的。所以再处理下end[i],表示是否存在以单个字母i为后缀的。
至于统计以i开头的不重复后缀的话,可以反向加入到Trie中统计。
#include <iostream> #include <cstdio> #include <algorithm> #include <vector> #include <cstring> using namespace std; typedef long long LL; const int M = 100005; const int N = 1005; int n , m , cnt[26] , end[26]; char a[N][N] , b[N][N]; LL ans = 0; struct Trie { int tot; struct trie { trie *next[26]; }s[M] , *root; trie *newnode () { trie *p = &s[tot ++]; memset (p -> next , 0 , sizeof(p -> next)); return p; } void init () { memset (cnt , 0 , sizeof(cnt)); tot = 0; root = newnode (); } void insert (char *s) { trie *p = root; for (int i = 0 ; s[i] ; i ++) { int c = s[i] - 'a'; if (p -> next[c] == NULL) { p -> next[c] = newnode (); } p = p -> next[c]; } } void cal (trie *p) { for (int i = 0 ; i < 26 ; i ++) { if (p -> next[i]) { cnt[i] ++; cal (p -> next[i]); } } } void gao (trie *p) { for (int i = 0 ; i < 26 ; i ++) { if (p -> next[i] == NULL) { if (p != root) ans += cnt[i]; } else { if (p != root && end[i]) ans ++; gao (p -> next[i]); } } } }suffix , prefix; int main () { while (scanf ("%d %d" , &n , &m) != EOF && n + m) { prefix.init ();suffix.init (); ans = 0; memset (cnt , 0 , sizeof (cnt)); memset (end , 0 , sizeof (end)); for (int i = 0 ; i < n ; i ++) { scanf ("%s" , a[i]); prefix.insert (a[i]); } for (int i = 0 ; i < m ; i ++) { scanf ("%s" , b[i]); reverse (b[i] , b[i] + strlen(b[i])); end[b[i][0] - 'a'] = 1; suffix.insert (b[i]); } suffix.cal (suffix.root); prefix.gao (prefix.root); printf ("%lld\n" , ans); } return 0; }