[关闭]
@lychee123 2017-07-11T14:33:48.000000Z 字数 1167 阅读 1413

UVA 1401:Remember the Word(字典树处理单词构成句子的方法数)

数据结构

题面链接

给你一个字符串s再给你n个小串s1,问用这些小串构成这个大串有多少种不同的方法。对于输出答案mod上20071027。

Sample Input
abcd // 大串s(长度小于 300 000)
4 //n(1 <= n <= 4000)
a
b
cd
ab //接下来的n个小串(长度都不超过100)
Sample Output
Case 1: 2

用字典树建树,将所有的小串放到字典树里。
对长串的每一位循环。沿着树往下走直到走到不能与长串匹配为止。此时循环到长串的下一位,依次找下去。

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. const int maxn=4e5+5;
  4. const int mod=20071027;
  5. int ch[maxn][30];//ch[i][j]表示在i节点标号为j的字母出现的节点位置
  6. int isword[maxn];//标记是否是一个单词的结尾
  7. int dp[maxn];
  8. char s[maxn],s1[105];
  9. int cnt=0;
  10. void insert(char s[])//字典树
  11. {
  12. int root=0;
  13. int l=strlen(s);
  14. for(int i=0;i<l;i++)
  15. {
  16. if(ch[root][s[i]-'a']==0)//该点还未出现过
  17. {
  18. ch[root][s[i]-'a']=++cnt;//建点
  19. }
  20. root=ch[root][s[i]-'a'];
  21. }
  22. isword[root]=1;//是一个单词的结尾
  23. }
  24. void f(int i)
  25. {
  26. int temp=dp[i-1];
  27. int root=0;
  28. while(1)//每个节点能够往后延伸的地方
  29. {
  30. root=ch[root][s[i]-'a'];
  31. if(root==0)
  32. break;
  33. if(isword[root]==1)//到达某个单词的结尾
  34. dp[i]=(dp[i]+temp)%mod;
  35. i++;//看下一位是否能继续匹配
  36. }
  37. }
  38. int main()
  39. {
  40. int t=0;
  41. while(~scanf("%s",s+1))
  42. {
  43. memset(ch,0,sizeof(ch));
  44. memset(dp,0,sizeof(dp));
  45. memset(isword,0,sizeof(isword));//清空不能忘!!
  46. int n;
  47. scanf("%d",&n);
  48. while(n--)
  49. {
  50. scanf("%s",s1);
  51. insert(s1);
  52. }
  53. int l=strlen(s+1);
  54. dp[0]=1;//这样才能往后累加啊
  55. for(int i=1;i<=l;i++)
  56. {
  57. if(dp[i-1])//说明之前是来到过这一位的。这里曾是某个单词的结尾。
  58. f(i);
  59. }
  60. printf("Case %d: %d\n",++t,dp[l]);
  61. }
  62. return 0;
  63. }

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注