题目
蓝书上的一道题, 给出一个长的字符串后给出n个短的字符串,问将短的字符串组合成长的字符串有多少种组合。
就比如:a, b, cd, ad可以组成abcd的四种方式:a+b+cd, ab+cd。
思路
先用短的字符串构建成Trie树,也就是短的字符串的集合。
令d(i)表示从字符i开始的字符串( 即后缀s[i….n] )的分解方案数。
则d(i) = sum{ d(i+len(x)) | 单词x是s[i….n]的前缀 }
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 300000 + 10, mod = 20071027;
char s[maxn];
char p[4010];
int n;
int sz;
int ch[maxn][26], val[maxn];
int d[maxn];
int idx(char c) { return c - 'a'; }
void insert(){
int u = 0, len = (int)strlen(p);
for(int i=0;i<len;i++){
int c = idx(p[i]);
if(!ch[u][c]) {
memset(ch[sz], 0, sizeof(ch[sz]));
ch[u][c]=sz++;
}
u = ch[u][c];
}
val[u]=1; // 标记结束
}
void init(){
int m;
n = (int)strlen(s);
sz=1;
memset(val, 0, sizeof(val));
memset(ch[0], 0, sizeof(ch));
scanf("%d", &m);
while(m--) {
scanf("%s", p);
insert();
}
}
void find(int id) {
int u=0;
d[id]=0;
for(int i = id; i < n; i++) {
int c=idx(s[i]);
if(!ch[u][c]) return;
u = ch[u][c];
if(val[u]) {
d[id]=(d[id]+d[i+1])%mod;
}
}
}
void solve(){
d[n]=1;
for(int i=n-1;i>=0;i--){
find(i);
}
cout << d[0] << endl;
}
int main(){
//freopen("input.txt", "r", stdin);
int kase=0;
while(~scanf("%s", s)) {
init();
printf("Case %d: ", ++kase);
solve();
}
return 0;
}