题意:给你s(s <= 4000)个不同单词组成的字典和一个字符串str(len <= 300000),str能分解若干个单词,问有几种分法(单词可以重复使用)。
思路: 把s个单词存入trie里,(str从1开始)用dp[i]表示str的子串(1-i)有几种分法。
从i+1开始在trie里找插入的单词,更新之后的dp。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <iostream>
using namespace std;
#define maxn 300005
const int mod = 20071027;
int dp[maxn];
char str[maxn];
struct trie {
int tot, c[500005][26];
int v[500005];
void init() {
tot = 0;
new_node();
}
int new_node() {
memset(c[tot], -1, sizeof(c[tot]));
v[tot] = 0;
return tot++;
}
void insert(char *s) {
int u = 0, i, k;
for(i = 0; s[i]; i++) {
k = s[i] - 'a';
if(c[u][k] == -1) c[u][k] = new_node();
u = c[u][k];
}
v[u]++;
}
void find(char *s, int j) { //从str的j位置开始在trie中找串
int u = 0, i, k;
for(i = j; s[i]; i++) {
k = s[i] - 'a';
if(c[u][k] == -1) return;
u = c[u][k];
if(v[u]) {
dp[i] += dp[j-1] * v[u];
if(dp[i] >= mod) dp[i] -= mod;
}
}
}
}a;
int main() {
int i, j, cas = 1, n;
char s[105];
while( ~scanf("%s", str+1)) {
a.init();
scanf("%d", &n);
while(n--) {
scanf("%s", s);
a.insert(s);
}
int len = strlen(str+1);
memset(dp, 0, sizeof(int)*(len+1));
dp[0] = 1;
for(i = 1; i <= len; i++) a.find(str, i);
printf("Case %d: %d\n", cas++, dp[len]);
}
return 0;
}