题目链接:
LA 3492
给一个由S个不同单词组成的字典和一个长字串。把这字符串分解为由若干个单词的连接,有多少种方法。
分析:
di
表示以第i个字母开头的方法数,则
di=sum{di+len(x)}
其中,x为S[i,,,,L]的前缀。用前缀树优化一下这样找前缀,最多需要100次。
复杂度
100∗105
#include <iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<vector>
#define maxn 300009
#define max_node 400009
#define sigma_size 26
#define MOD 20071027
using namespace std;
struct Trie
{
int ch[max_node][sigma_size];
int sz = 0;
int val[max_node];
void clear(){sz = 1 ; memset(ch[0],0,sizeof(ch[0]));}
int idx(char c){return c-'a';};
void add(char *s,int v)
{
int next = 0,n = strlen(s);
for(int i = 0 ; i<n ; ++i)
{
int c = idx(s[i]);
if(!ch[next][c])
{
memset(ch[sz],0,sizeof(ch[sz]));
val[sz] = 0;
ch[next][c] = sz++;
}
next = ch[next][c];
}
val[next] = v;
}
void find_pre(char *s,int len,vector<int>& ans)
{
int u =0;
for(int i=0 ;i<len ; ++i)
{
if(s[i]==0)break;
int c = idx(s[i]);
if(!ch[u][c])break;
u = ch[u][c];
if(val[u])ans.push_back(val[u]);
}
}
};
Trie trie;
char str[maxn];
int S;
int d[maxn];
char P[109];
vector<int> ans;
int main()
{
//freopen("H:\\c++\\file\\stdin.txt","r",stdin);
int kase = 0;
while(scanf("%s%d",str,&S)==2)
{
trie.clear();
while(S--)
{
scanf("%s",P);
trie.add(P,strlen(P));
}
int L = strlen(str);
memset(d,0,sizeof(d[0])*L);
d[L] = 1;
for(int i = L - 1; i>=0 ; --i)
{
ans.clear();
trie.find_pre(str+i,L-i,ans);
for(int j = 0 ; j<ans.size() ; ++j)
d[i] = (d[i]+d[i+ans[j]])%MOD;
/*cout<<"d["<<i<<"]"<<d[i]<<"\n";
for(int j=0 ; j<ans.size() ; ++j)
cout<<ans[j]<<"\n";
printf("\n----------------------\n");*/
}
printf("Case %d: %d\n",++kase,d[0]);
}
return 0;
}