题意 给你m个短字符串和一个长串,问你长串拆分成由短串组成的方法数。
思路 dp[i] 表示从i开始的长串后缀,可以用短串组成的方案数。dp[i] += dp[i+len(x)] 其中x是从i开始的长串后缀的前缀,这个前缀属于短串集合。初始条件dp[n] = 1.
用短串建立Trie树,用长串后缀去在字典树上匹配,找到满足条件的短串,更新dp
注意:Trie树的maxnode要开够!!被这个点WA死了….
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
#include <assert.h>
using namespace std;
const int maxn = 310005;
const int MOD = 20071027;
const int maxlen = 110;
const int maxnum = 4000;
const int sigmasize = 26;
const int maxnode = maxnum*maxlen;
struct Trie{
//内容存的是节点i,遇到j字符时,前往的节点号
int ch[maxnode][sigmasize];
int val[maxnode];
int sz;
char ji;
void init(char j = 'a'){
ji = j;
sz = 1;
memset(ch[0],0,sizeof(ch[0]));
}
int idx(char c){
return c - ji;
}
//插入一个单词
void insert(char* s,int v)
{
assert(v != 0);
int now = 0;
int n = strlen(s);
for(int i=0;i<n;i++)
{
int c = idx(s[i]);
if(!ch[now][c]){
memset(ch[sz],0,sizeof(ch[sz]));
val[sz] = 0;
ch[now][c] = sz++;
}
now = ch[now][c];
}
val[now] = v;
}
//查找一个单词是否在字典树中,在返回val,不在,返回0
int find(char* str)
{
int now = 0;
while(*str != 0)
{
int p = idx(*str);
if(!ch[now][p])
{
return 0;
}
now = ch[now][p];
str++;
}
return val[now];
}
};
Trie tree;
int dp[maxn];
char str[maxn];
int n,m;
char tmp[maxlen];
int main()
{
int i,j,t;
t = 0;
while(scanf("%s",str) != EOF)
{
t++;
tree.init();
n = strlen(str);
scanf("%d",&m);
for(i=0;i<m;i++)
{
scanf("%s",tmp);
tree.insert(tmp,/*strlen(tmp)*/1);
}
memset(dp,0,sizeof(dp));
dp[n] = 1;
for(i=n-1;i>=0;i--)
{
int now = 0;
for(j=0;i+j<n;j++)
{
int c = tree.idx(str[i+j]);
if(!tree.ch[now][c]){
break;
}
now = tree.ch[now][c];
if(tree.val[now] != 0)
{
dp[i] = (dp[i] + dp[i+j+1]) % MOD;
}
}
}
cout<<"Case "<<t<<": "<<dp[0]<<endl;
}
return 0;
}