题目大意:给出一个由S个不同单词组成的字典和一个长字符串.把这个字符串分解成若干个单词的链接(单词可以重复使用),问有多少种方法.
题目思路:一个裸的Trie树和DP的结合.
代码如下:
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxnode = 4000*100 + 100;
const int sig_size = 26;
const int maxn = 300005;
const int mod = 20071027;
char s[maxn];
int dp[maxn];
struct Trie{
int ch[maxnode][sig_size];
int val[maxnode];
int sz;
Trie(){
sz = 1;
memset(ch[0], 0, sizeof(ch));
}
int idx(char c){
return c-'a';
}
void clear(){
sz = 1;
memset(ch[0], 0, sizeof(ch));
}
void insert(char* s, int v){
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] = v;
}
bool search(char* s, int len){
int u = 0;
for(int i = 0; i < len; i++){
int c = idx(s[i]);
if(!ch[u][c]) return false;
u = ch[u][c];
}
if(val[u]) return true;
else return false;
}
};
Trie T;
int main(){
int m, len, cas = 1;
char c[105];
while(~scanf("%s", s)){
T.clear();
len = strlen(s);
scanf("%d", &m);
while(m--){
scanf("%s", c);
T.insert(c, 1);
}
memset(dp, 0, sizeof(dp));
dp[len] = 1;
for(int i = len - 1; i >= 0; i--){
for(int j = 1; j <= 100 && i+j <= len; j++){
if(T.search(s+i, j)){
dp[i] = (dp[i+j] + dp[i])%mod;
}
}
}
printf("Case %d: %d\n", cas++, dp[0]);
}
return 0;
}