chuninsane

UVALive 3942 Remember the Word(字典树+DP)

题目链接:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1943

题意:一个长字符串和多个短字符串,求短字符串有多少种方式组成长字符串。

状态转移方程: dp[i] = sum(d[i + len(x)])  (x是s[i...L]的前缀) 

对于每个i,如果直接暴力寻找s[i...L]的前缀,复杂度为O(nm) (n为短字符串的个数,m为短字符串的长度),肯定会超时。

既然是求前缀,那么可以使用前缀树(字典树)来解决此问题。用字典树寻找前缀的复杂度为O(m)。

#include <cstdio>
#include <iostream>
#include <cstring>
#define maxn 400100
#define maxm 300010
#define mod 20071027
#define sigma_size 26
using namespace std;

char str[maxm], tstr[110];
int dp[maxm], ch[maxn][sigma_size], val[maxn], sz;

struct Trie
{
    int get_id(char c)
    {
        return c - 'a';
    }
    
    void insert(char* str, int v)
    {
        int u = 0, len = (int)strlen(str);
        for (int i = 0; i < len; ++i)
        {
            int id = get_id(str[i]);
            if (!ch[u][id])
            {
                memset( ch[sz], 0, sizeof(ch[sz]));
                val[sz] = 0;
                ch[u][id] = sz++;
            }
            u = ch[u][id];
        }
        val[u] = v;
    }
    
    int query(char* str, int start)
    {
        int u = 0, result = 0, len = (int)strlen(str), next;
        for (int i = 0; i < len; ++i)
        {
            int id = get_id(str[i]);
            next = ch[u][id];
            if (next)
            {
                if (val[next])
                    result = (result + dp[i + start + 1])%mod;
            }
            else
                break;
            u = next;
        }
        return result;
    }
};

void init();

int main(void)
{
    int ca = 1, n;
    while (scanf("%s", str) != EOF)
    {
        init();
        int len = (int)strlen(str);
        
        scanf("%d", &n);
        Trie trie = Trie();
        while (n--)
        {
            scanf("%s", tstr);
            trie.insert( tstr, 1);
        }
        
        dp[len] = 1;
        for (int i = len - 1; i >= 0; i--)
        {
            dp[i] = trie.query( str + i, i);
        }
        printf("Case %d: %d\n", ca++, dp[0]);
    }
    return 0;
}

void init()
{
    sz = 1;
    memset( dp, 0, sizeof(dp));
    memset( ch[0], 0, sizeof(ch[0]));
    memset( val, 0, sizeof(val));
}

 

posted on 2015-10-30 16:03  chuninsane  阅读(114)  评论(0编辑  收藏  举报

导航