題目鏈接:http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=22109;
思路:dp[i]表示原串從i開始的後段子串的方案數,從後往前dp,然後dp[i] = sum(dp[i + len(x)],這裏的x是給出單詞並且是這後段的前綴串。如果直接枚舉的話會超時,先把單詞全部加到字典樹上面然後在字典樹上面查找就可以了。我是用指針的寫法,記住每組數據輸出後一定要初始化字典樹!
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<map>
#include<cstring>
#include<map>
#include<set>
#include<queue>
#include<stack>
#include<cmath>
using namespace std;
const double eps = 1e-10;
const int inf = 0x7fffffff, N = 3e5 + 10, mo = 20071027;
typedef long long ll;
using namespace std;
struct trie
{
int data;
trie *Next[26];
trie()
{
data = 0;
memset(Next, 0, sizeof(Next));
}
};
char s[N], x[110];
int dp[N], len;
trie *root;
void trie_insert(char *str)
{
trie *p = root;
for(int i = 0; str[i]; i++)
{
int ch = str[i] - 'a';
if(p->Next[ch] == NULL) p->Next[ch] = new trie;
p = p->Next[ch];
}
p->data++;
}
int trie_find(char *str, int sta)
{
int cnt = 0;
trie *p = root;
for(int i = 0; str[i]; i++)
{
int ch = str[i] - 'a';
p = p->Next[ch];
if(p == NULL) return cnt;
if(p->data) cnt = (cnt + dp[i + sta + 1])%mo;
}
return cnt;
}
void del(trie * p)
{
if(p == NULL)
return ;
else
{
for(int i = 0; i<26; i++)
del(p->Next[i]);
}
delete p;
}
int main()
{
int n, cas = 1;
while(~scanf("%s", s))
{
root = new trie;
scanf("%d", &n);
memset(dp, 0, sizeof(dp));
len = strlen(s);
dp[len] = 1;
for(int i = 1; i<=n; i++)
{
scanf("%s",x);
trie_insert(x);
}
for(int i = len - 1; i>=0; i--)
dp[i] = trie_find(s+i, i);
printf("Case %d: %d\n", cas++, dp[0]);
del(root);
}
return 0;
}