UVA-1401-dp+Trie

https://vjudge.net/problem/UVA-1401题目链接

 给出一个文本串和若干个单词,问由这些单词组成这个文本的不同方案个数

例 abc=a+b+c=ab+c=a+bc=abc  为他的所有可能的组合

  方程不难推出一个f[i]=SUM{f[j+1] | j>=i&&s[i,,j]是一个单词 } //其中f[i]表示s[i...sz]的方案个数,如果依次枚举判断这个前缀是不是一个单词的话复杂度达到O(sz^2)太大了,可以建一颗字典树每次从根出发沿着后面的单词走,遇到have为1表示单词存在累加答案否则跳过,走不下去时退出,由于深度最大100,复杂度就是O(100*sz);

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define LL long long
 4 const int MOD=20071027;
 5 char s[300010];
 6 int ch[200010][26];
 7 bool have[300010];
 8 int f[300010];
 9 int size=0;
10 void insert(char *S)
11 {
12     int n=strlen(S),u=0;
13     for(int i=0;i<n;++i){
14         int c=S[i]-'a';
15         if(!ch[u][c]) ch[u][c]=size++;
16         u=ch[u][c];
17     }
18     have[u]=1;
19 }
20 int main()
21 {
22     char str[110];
23     int cas=0;
24     while(cin>>s+1){
25         int ans=0;
26         size=1;
27         memset(ch,0,sizeof(ch));
28         memset(have,0,sizeof(have));
29         int sz=strlen(s+1);
30         int n,i;
31         cin>>n;
32         for(i=1;i<=n;++i)
33         {
34             scanf("%s",str);
35             insert(str);
36         }
37         f[sz+1]=1;
38         for(i=sz;i>=1;--i)
39         {
40             f[i]=0;
41             int j=i;
42             int u=0;
43             while(j<=sz&&ch[u][s[j]-'a']){
44                 u=ch[u][s[j]-'a'];
45                 if(have[u]) f[i]=(f[i]+f[j+1])%MOD;
46                 j++;
47             }
48         }
49          //if(cas>=1)puts("");
50         printf("Case %d: ",++cas);
51         cout<<f[1]<<endl;
52     }
53     return 0;
54 }
原文地址:https://www.cnblogs.com/zzqc/p/8402233.html