UVALIVE 5792 Trie+统计

题意:给你两种串,一种可以当前缀,一种可以当后缀,问两种串合起来,一共有多少种组合。并且没有重合。

思路:我们先将两种串插入字典树,对于后缀串,我们反向插入,然后处理出每个字符对应的后缀的个数。

我们来看一个组合的串,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 ;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值