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; }