UVa1401 Remember the Word(DP+Trie树)
题目给定一个字符串集合有几种方式拼成一个字符串。
- dp[i]表示stri...strlen-1的方案数
- dp[len]=1
- dp[i]=∑dp[j](stri...strj-1∈SET)
用集合的字符串构造一棵Trie树,然后就可以在线性时间判断哪几个前缀字符串在集合里。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 int ch[410000][26],tn; 6 bool flag[410000]; 7 void insert(char *s){ 8 int x=0; 9 for(int i=0; s[i]; ++i){ 10 int y=s[i]-'a'; 11 if(ch[x][y]==0) ch[x][y]=++tn; 12 x=ch[x][y]; 13 } 14 flag[x]=1; 15 } 16 char word[333333]; 17 int d[333333]; 18 int main(){ 19 int t=0,n; 20 char str[111]; 21 while(~scanf("%s",word)){ 22 tn=0; 23 memset(ch,0,sizeof(ch)); 24 memset(flag,0,sizeof(flag)); 25 scanf("%d",&n); 26 while(n--){ 27 scanf("%s",str); 28 insert(str); 29 } 30 memset(d,0,sizeof(d)); 31 int len=strlen(word); 32 d[len]=1; 33 for(int i=len-1; i>=0; --i){ 34 int x=0; 35 for(int j=i; j<len; ++j){ 36 int y=word[j]-'a'; 37 if(ch[x][y]==0) break; 38 x=ch[x][y]; 39 if(flag[x]) d[i]+=d[j+1],d[i]%=20071027; 40 } 41 } 42 printf("Case %d: %d\n",++t,d[0]); 43 } 44 return 0; 45 }