这道题目主用递推做。
设一个单词W,由(w1,w2,···,wn)个字母组成,判断其有多少种单词的组合方法。
给定任意一个后缀(wi,wi+1,···,wn),想要判断有多少种组合方法,就要找到它的前缀。不妨设(wi,wi+1,···,wn)这个后缀的前缀为x,就要找到这个后缀有多少个前缀(这里所说的前缀是说的是单词)。不妨设d(i)表示从i到n这个后缀有多少种组合方法,设x为这个后缀种的前缀,剩下的那部分字符串为y。那么d(i) = d(len(x)+i)。
为什么呢?一个前缀至少对应一种组合,但是这个组前缀不一定是符合的,需要判断y是不是单词。因此还需要判断d(len(x)+i)有多少种组合。因为一个后缀中有多个前缀,所以要对所有的前缀求和。即有下面的递推关系式:
d(i) = sum{d(len(x)+i)}
所以用Trie树可以快速的找出前缀。
下面是代码:
#include<stdio.h>
#include<string.h>
#define maxn 500010
int ch[maxn][26];
int val[maxn],cnt,n;
int d[maxn];
char str[maxn],s[110];
void initi()
{
cnt = 1;
memset(ch[0],0,sizeof(ch[0]));
memset(d,0,sizeof(d));
}
void insert_Trie(char *s)
{
int u = 0;
while(*s)
{
int id = *s - 'a';
if(ch[u][id] == 0)
{
memset(ch[cnt],0,sizeof(ch[cnt]));
val[cnt] = 0;
ch[u][id] = cnt++;
}
u = ch[u][id];
s++;
}
val[u] = -1;
}
int main()
{
int c = 0;
while(scanf("%s",str) != EOF)
{
c++;
initi();
scanf("%d",&n);
for(int i = 0; i < n; i++)
{
scanf("%s",s);
insert_Trie(s);
}
int len = strlen(str);
d[len] = 1;
for(int i = len-1; i >= 0; i--)
{
int j,k;
int u = 0;
for(j = 0,k = i; k < len; j++,k++)
{
int id = str[k] - 'a';
if(!ch[u][id]) break;
else if(val[ch[u][id]] == -1)
{
d[i] += d[i+j+1];
if(d[i] >= 20071027) d[i] %= 20071027;
}
u = ch[u][id];
}
}
printf("Case %d: ",c);
printf("%d\n",d[0]%20071027);
}
return 0;
}
注:
一、当找前缀时不用query操作
二、结果很大,int会爆,需要处理一下,因为是mod。