大白书上的题。先对那100个单词建树,然后把那个长度30万的单词从后往前枚举逐步查询,查询的时候就可以进行递推求,dp[i] 等于i这个位置之后有的方案数,然后在从i到len-1查询过程中,如果查到j发觉是有的即i到j这段存在,那么dp[i]就可以加上dp[j],这样下去,答案就是dp[0],不过记得要初始化dp[len]=1,我用的是左开右闭的方法,所以如果当前位置可达,那么就是dp[i]加上当前位置后面一个,所以会出现加上dp[len],如果加上这个了就说明已经可达了。
AC代码:
#include<cstdio>
#include<ctype.h>
#include<algorithm>
#include<iostream>
#include<cstring>
#include<vector>
#include<cstdlib>
#include<stack>
#include<cmath>
#include<queue>
#include<set>
#include<ctime>
#include<string.h>
#include<string>
using namespace std;
#define ll long long
#define MOD 20071027
char a[300005];
int dp[300005];
struct Trie
{
int ch[400005][26];
int val[400005];
int sz;
Trie(){sz = 1; memset(ch[0],0,sizeof(ch[0]));}
void clear()
{
sz = 1;
memset(ch[0],0,sizeof(ch[0]));
}
int idx(char c){return c-'a';}
void insert(char *s, int v)
{
int u = 0, n = strlen(s);
for(int i = 0; i < n; i++)
{
int c = idx(s[i]);
if(!ch[u][c])
{
memset(ch[sz],0,sizeof(ch[sz]));val[sz] = 0;ch[u][c] = sz++;
}
u = ch[u][c];
}
val[u] = v;
}
void query(char *s,int f,int e)
{
int u = 0;
for(int i = f; i < e; i++)
{
int c = idx(s[i]);
if(!ch[u][c]) break;
if(val[ch[u][c]])
{
dp[f]=(dp[f]+dp[i+1])%MOD;
}
u = ch[u][c];
}
}
};
Trie T;
int main()
{
#ifdef GLQ
freopen("input.txt","r",stdin);
// freopen("o.txt","w",stdout);
#endif // GLQ
char temp[105];
int s,i,j,cas = 1;
while(~scanf("%s",a))
{
T.clear();
scanf("%d",&s);
for(i = 0; i < s; i++)
{
scanf("%s",temp);
T.insert(temp,1);
}
int len = strlen(a);
memset(dp,0,sizeof(dp));
dp[len] = 1;
for(i = len-1; i >= 0; i--)
T.query(a,i,len);
printf("Case %d: %d\n",cas++,dp[0]);
}
return 0;
}