fork download
  1. #include<bits/stdc++.h>
  2. using namespace std;
  3.  
  4. // mx: độ dài tối đa chuỗi S
  5. const int mx = 5005;
  6. // mx_trie: Tổng số lượng ký tự của tất cả các từ trong từ điển cộng lại (10^6)
  7. // Đây là số node tối đa có thể sinh ra.
  8. const int mx_trie = 1e6 + 5;
  9. const int MOD = 1e9 + 7;
  10.  
  11. string s;
  12. int k;
  13. int dp[mx];
  14.  
  15. // --- PHẦN TRIE MẢNG TĨNH ---
  16.  
  17. // trie[u][c]: Lưu chỉ số (ID) của node con khi đi từ node u qua cạnh c.
  18. // Thay vì node->child[c], ta dùng trie[u][c].
  19. // u là ID của node hiện tại (Gốc luôn là 0).
  20. // c là ký tự (đã chuyển về số 0-25).
  21. int trie[mx_trie][26];
  22.  
  23. // is_end[u]: Đánh dấu node có ID là u có phải là kết thúc của một từ không.
  24. bool is_end[mx_trie];
  25.  
  26. // nodes: Biến đếm toàn cục để cấp phát ID mới cho các node.
  27. // Ban đầu nodes = 0 (là gốc).
  28. int nodes = 0;
  29.  
  30. // Hàm thêm từ vào Trie
  31. void add(string &t) {
  32. int u = 0; // Bắt đầu từ gốc (ID = 0)
  33. for(char c : t) {
  34. int v = c - 'a'; // Chuyển 'a'->0, 'b'->1...
  35.  
  36. // Nếu từ u chưa có đường đi v (chưa có con)
  37. if(!trie[u][v]) {
  38. trie[u][v] = ++nodes; // Cấp phát ID mới cho node con và gán vào
  39. }
  40.  
  41. // Di chuyển u xuống node con
  42. u = trie[u][v];
  43. }
  44. // Kết thúc vòng lặp, u đang đứng ở node cuối cùng của từ t
  45. is_end[u] = true; // Đánh dấu đây là điểm kết thúc từ
  46. }
  47.  
  48. int main()
  49. {
  50. cin.tie(0)->sync_with_stdio(0);
  51. if(fopen("Word_Combinations.inp","r"))
  52. {
  53. freopen("Word_Combinations.inp","r",stdin);
  54. freopen("Word_Combinations.out","w",stdout);
  55. }
  56.  
  57. cin >> s >> k;
  58. int n = s.size();
  59.  
  60. // Đọc k từ và ném vào Trie
  61. while(k--) {
  62. string t;
  63. cin >> t;
  64. add(t);
  65. }
  66.  
  67. // DP:
  68. // dp[i] là số cách tạo ra tiền tố s[0...i-1]
  69. dp[0] = 1; // Tiền tố rỗng có 1 cách
  70.  
  71. for(int i=0; i<n; ++i) {
  72. // Nếu không thể tạo ra tiền tố đến i thì bỏ qua (nhánh cụt)
  73. if(!dp[i]) continue;
  74.  
  75. // Bắt đầu dò từ node gốc của Trie
  76. int u = 0;
  77.  
  78. // Dò tiếp các ký tự tiếp theo trong chuỗi S bắt đầu từ i
  79. for(int j=i; j<n; ++j) {
  80. int v = s[j] - 'a';
  81.  
  82. // Nếu trên Trie không có đường đi tiếp -> Không khớp từ nào -> Dừng
  83. if(!trie[u][v]) break;
  84.  
  85. // Nhảy đến node tiếp theo
  86. u = trie[u][v];
  87.  
  88. // Nếu tại u là điểm kết thúc của một từ trong từ điển
  89. // Nghĩa là đoạn s[i...j] là một từ hợp lệ
  90. if(is_end[u]) {
  91. // Cộng dồn số cách từ dp[i] sang dp[j+1]
  92. dp[j+1] = (dp[j+1] + dp[i]) % MOD;
  93. }
  94. }
  95. }
  96.  
  97. cout << dp[n];
  98. return 0;
  99. }
  100.  
Success #stdin #stdout 0.01s 5288KB
stdin
Standard input is empty
stdout
1