UVAlive 5792 Diccionário Portuñol (Trie)

来源:互联网 发布:乐器模拟软件排行 编辑:程序博客网 时间:2024/05/02 00:41

转载请注明出处,谢谢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;}