【题意】给出一个有S个不同单词组成的字典和一个字符串。把这个字符串分解成若干个单词的连接,有多少种方法?
【解题方法】令dp[i]表示以字符i结束的字符串的分解方案数,即dp[i+j] = sum(dp[i]) (j为一个单词的长度),初始化dp[0] = 1;把所有单词组成Trie,然后试着在Trie中查找单词即可。
【代码君】
//
//Created by just_sort 2016/10/12
//Copyright (c) 2016 just_sort.All Rights Reserved
//
#include <set>
#include <map>
#include <queue>
#include <stack>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int maxn = 444444;
const int maxm = 26;
const int mod = 20071027;
int dp[333333];
char s[333333];
struct Trie{
int ch[maxn][maxm],val[maxn],root,sz;
int newnode(){
val[sz] = 0;
memset(ch[sz],0,sizeof(ch[sz]));
return sz++;
}
void init(){
sz = 0;
root = newnode();
}
void insert(char *s,int v){
int len = strlen(s);
int u = root;
for(int i = 0; i < len; i++){
int now = s[i] - 'a';
if(!ch[u][now]){
ch[u][now] = newnode();
}
u = ch[u][now];
}
val[u] = v;
}
// int find(char *s){
// int len = strlen(s);
// int u = root;
// for(int i = 0; i < len; i++){
// int now = s[i] - 'a';
// if(!ch[u][now]) return 0;
// u = ch[u][now];
// }
// return val[u];
// }
}trie;
int main()
{
int ks = 1, n;
while(scanf("%s",s+1)!=EOF)
{
trie.init();
scanf("%d",&n);
for(int i = 1; i <= n; i++){
char op[110];
scanf("%s",op);
trie.insert(op, 1);
}
int len = strlen(s+1);
memset(dp, 0, sizeof(dp));
dp[0] = 1; s[0] = '$';
for(int i = 0; s[i]; i++)
{
int u = 0;
for(int j = 1; j <= len; j++){
int now = s[i+j] - 'a';
u = trie.ch[u][now];
if(!u) break;
else if(trie.val[u] == 1){
dp[i+j] = (dp[i+j] + dp[i]) % mod;
}
}
}
printf("Case %d: %d\n",ks++,dp[len]);
}
return 0;
}