UVALive - 3942 Remember the Word (Trie + DP)

题意:

给定一篇长度为L的小写字母文章, 然后给定n个字母, 问有多少种方法用这些字母组成文章。

思路:

用dp[i]来表达[i , L]的方法数, 那么dp[i] 就可以从dp[len(x) + i]转移过来, 注意dp[L+1]要初始化为1.

递推写法

#include <bits/stdc++.h>
using namespace std;
const int maxN = 3e5 + 7;
const int mod =  20071027;
char in[maxN];
int n;
struct Trie {
    int ch[maxN][26];
    int val[maxN];
    int sz;
    void Init(){sz = 1; memset(ch[0], 0, sizeof(ch[0])); memset(val, 0, sizeof(val));}
    int idx(char c) {return c - 'a';}
    void Insert(char *s){
        int u = 0, n = strlen(s);
        for(int i = 0; i < n; i++){
            int c = idx(s[i]);
            if(!ch[u][c]){
                memset(ch[sz], 0, sizeof(ch[sz]));
                val[sz] = 0;
                ch[u][c] = sz++;
            }
            u = ch[u][c];
        }
        val[u] = n;
    }

}tree;
long long dp[maxN];
int main(){
//    freopen("1.txt","r", stdin);
    int kase = 1;
    while(~scanf("%s", in)){
        tree.Init();
        memset(dp , 0 , sizeof(dp));
        scanf("%d", &n);
        char word[100];
        for(int i = 0; i < n; i++){
            scanf("%s", word);
            tree.Insert(word);
        }
        int len = strlen(in);
        dp[len] = 1;
        for(int pos = len ; pos >= 0; pos--){
            int u = 0;
            for(int i = pos, wordLen = 1; i < len; i++, wordLen++){
                int c = tree.idx(in[i]);
                if(tree.ch[u][c] == 0) break;
                u = tree.ch[u][c];
                if(tree.val[u] != 0){
                    dp[pos] += dp[pos + wordLen];
                    dp[pos] %= mod;
                }
            }
        }
        printf("Case %d: %lld\n", kase++, dp[0]);
    }

    return 0;
}

记忆化搜索

#include <bits/stdc++.h>
using namespace std;
const int maxN = 2e6 + 7;
const int mod =  20071027;
char in[maxN];
int n;
struct Trie {
    int ch[maxN][26];
    int val[maxN];
    int sz;
    void Init(){
        sz = 1;
        memset(ch[0], 0, sizeof(ch[0]));
        memset(val, 0, sizeof(val));
    }
    int idx(char c) {return c - 'a';}
    void Insert(char *s){
        int u = 0, n = strlen(s);
        for(int i = 0; i < n; i++){
            int c = idx(s[i]);
            if(!ch[u][c]){
                memset(ch[sz], 0, sizeof(ch[sz]));
                val[sz] = 0;
                ch[u][c] = sz++;
            }
            u = ch[u][c];
        }
        val[u] = n;
    }

}tree;

long long dp[maxN];
int dfs(int pos){
    int temp = pos;
    if(dp[pos] > 0) return dp[pos];
    int ret = 0;
    int adr = 0;
    while(tree.ch[adr][in[pos] - 'a']){
        adr = tree.ch[adr][in[pos] - 'a'];
        if(tree.val[adr] != 0){
            ret = (ret + dfs(pos + 1)) % mod;
        }
        pos ++;

    }
    dp[temp] = ret;
    return ret;
}

int main(){
    freopen("1.txt","r", stdin);
    int ncase = 1;
    while(~scanf("%s", in)){
        tree.Init();
        scanf("%d", &n);
        char word[100];
        for(int i = 0; i < n; i++){
            scanf("%s", word);
            tree.Insert(word);
        }

        int l = strlen(in);
        for(int i = 0;i <= l; i ++)dp[i] = 0;
        dp[l] = 1;
        printf("Case %d: %d\n",ncase ++ , dfs(0));
    }

    return 0;
}

 

posted @ 2018-08-08 20:25  Neord  阅读(151)  评论(0编辑  收藏  举报