uvalive3942:https://icpcarchive.ecs.baylor.edu/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=1943
题意:给以一个串,然后给你一些单词,问你这个串由这些单词组成的话,可以有多少种组成方式。
题解:这是白书上的一道题目。开始,觉得是DP,但是不知道怎么搞。看了白书上的解释,慢慢的才弄了出来。用dp【i】表示从i到strlen(s)-1最多的组成方式,即以字符i开头。这样的话,就很明显了,dp【i】=sum(dp[i+len(x)])(x是i.....len-1的前缀),那么只要查询i....len-1之间的前缀,如果找到一个前缀,就更新。通过这一题,有了更深的体会,Trie树的另外一个名字,前缀树。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<algorithm> 5 #define maxn 1100000 6 using namespace std; 7 int dp[300002]; 8 char str[300002]; 9 int current; 10 struct Nod { //0为无效值 11 int lnk[26], val; 12 char ss[28]; 13 void init() { 14 memset(lnk, 0, sizeof(lnk)); 15 memset(ss, 0, sizeof(ss)); 16 val = 0; 17 } 18 }; 19 const char BASE = 'a'; 20 struct Trie { 21 Nod buf[maxn]; 22 int len; 23 void init() { 24 buf[len=0].init(); 25 } 26 void insert(char * str) { 27 int now = 0; 28 for(int i = 0; str[i]; i ++) { 29 int & nxt = buf[now].lnk[str[i]-BASE]; 30 if(!nxt)buf[nxt=++len].init(); 31 now = nxt; 32 } 33 buf[now].val=1; 34 } 35 void search(char * str) { 36 int now = 0; 37 for(int i = 0; str[i]; i ++) { 38 int & nxt = buf[now].lnk[str[i]-BASE]; 39 now = nxt; 40 if(!nxt)return;//注意这里的返回,不然会tle 41 if(buf[now].val==1){ 42 dp[current]=(dp[current]+dp[current+i+1])%20071027; 43 } 44 } 45 } 46 } trie; 47 int n; 48 char ss[103]; 49 char s1[300002]; 50 int main(){ 51 int tt=1; 52 while(~scanf("%s",str)){ 53 trie.init(); 54 scanf("%d",&n); 55 memset(dp,0,sizeof(dp)); 56 while(n--){ 57 scanf("%s",ss); 58 trie.insert(ss); 59 } 60 int len=strlen(str); 61 dp[len]=1; 62 for(int i=len-1;i>=0;i--){ 63 current=i; 64 trie.search(str+i); 65 } 66 printf("Case %d: %d ",tt++,dp[0]); 67 } 68 }