LA3942字典树+递推

题意:
     给你一个字典,最多4000个单词,每个单词长度最多是100,然后给你一个串,问你这个子串可以被那些单词组合的组合数,比如字典里有4个单词a b ab cd,然后给你一个串abcd则abcd = a+b+cd,ab+cd一共两种组合。输出组合数对20071027取余(白书上写错了写的是20071207)


思路:
       我们可以找到一个递推公式,d[i] = sum(i + len[x]),解释一下这个,d[i]表示的是以i个位置为开头的字符串的组合个数,就是[i,i+1,i+2..len-1],而x则是以i开头的那个串的前缀,这样就不难理解了吧,整体意思就是如果defg = 5,那么只要存在bc,就可以得到以a开头的abcdefg可以加上5了,然后就是优化时间,因为直接暴力写的话30000*4000*判断前缀匹配,时间复杂度接受不了,既然是前缀,我们可以想到字典树,我们可以把所有的4000个单词都放到字典里,然后在匹配的时候如果碰到单词末尾节点,直接就是找到满足条件,更新左右值,就行了,具体看代码,很容易理解。
PS不要把30000的那个字符串拆开放到字典树里,一开始我就是这么想的,结果还没敲完意识到这样内存会很大,很可能会爆内存,还有就是别忽视strlen这个函数的时间复杂度,TLE了一次。
      




#include<stdio.h>
#include<string.h>
#include<stdlib.h>


#define N 300000 + 10
#define MOD 20071027


typedef struct Tree
{
    Tree *next[26];
    int mk;
}Tree;


Tree root;
char Str[N];
long long dp[N];


void BuidTree(char *str)
{
    int len = strlen(str);
    Tree *p = &root ,*q;
    for(int i = 0 ;i < len ;i ++)
    {
        int id = str[i] - 'a';
        if(p -> next[id] == NULL)
        {
            q = (Tree *)malloc(sizeof(root));
            q -> mk = 0;
            for(int j = 0 ;j < 26 ;j ++)
            q -> next[j] = NULL;
            p -> next[id] = q;
            p = p -> next[id];
        }
        else
        p = p -> next[id];
    }
    p -> mk = 1;
}


void Query(char *str ,int ii ,int len)
{
    dp[ii] = 0;
    Tree *p = &root;
    for(int i = ii ;i < len ;i ++)
    {
        int id = str[i] - 'a';
        p = p -> next[id];
        if(p == NULL) break;
        if(p -> mk) dp[ii] = (dp[ii] + dp[i+1]) % MOD;
    }
    return ;
}


int main ()
{
    int cas = 1 ,i ,n;
    char tmp[105];
    while(~scanf("%s" ,Str))
    {
        scanf("%d" ,&n);
        for(i = 0 ;i < 26 ;i ++)
        root.next[i] = NULL;
        for(i = 1 ;i <= n ;i ++)
        {
            scanf("%s" ,tmp);
            BuidTree(tmp);
        }
        int len = strlen(Str);
        dp[len] = 1;
        for(i = len - 1 ;i >= 0 ;i --)
        {
            Query(Str ,i ,len);//把len直接传下去,别在里面从求,会超时。
        }
        printf("Case %d: %lld " ,cas ++ ,dp[0]);
    }
}









原文地址:https://www.cnblogs.com/csnd/p/12062539.html