UVA1401 【Remember the Word】
阿新 • • 發佈:2021-06-18
知識點:dp+trie
這道題顯然是從前往後dp的,題解區裡還沒有這樣的題解,我就來發一波(題解區裡也有提到不過並沒有做詳細的說明也沒有程式碼)。
思路和從後往前的基本一樣。
設 \(dp_i\)代表字首 \(s_{1...i}\) 有多少種不同的組成方式。
很容易想到轉移方程:
如果一個模式串 \(t\) 是字首 \(s_{1...i}\) 的字尾,則 \(dp_i += dp_{i-|t|}\)。
如果暴力去判斷的話複雜度是 \(O(nm)\) 的,這道題過不去,所以我們要考慮優化。
我們發現每個模式串最長也才 \(100\),考慮將所有模式串倒序建成一個 \(trie\)。
對於 \(s\)
因為模式串最長 \(100\),即 \(trie\) 樹的深度最大才 \(100\),所以複雜度是\(O(100n)\)的。
多組資料注意初始化。
#include <bits/stdc++.h> using namespace std; int trie[400010][26], tot; char s[300010], t[110]; int n, m; int End[400010], dp[300010]; int cnt; int main() { while (scanf("%s", s + 1) != EOF) { tot = 1; memset(End, 0, sizeof(End)); memset(trie, 0, sizeof(trie)); cnt++; n = strlen(s + 1); scanf("%d", &m); for (int i = 1, len, p; i <= m; i++) { scanf("%s", t + 1); len = strlen(t + 1); p = 1; for (int j = len; j; j--) { if (!trie[p][t[j] - 'a']) trie[p][t[j] - 'a'] = ++tot; p = trie[p][t[j] - 'a']; } End[p]++; } memset(dp, 0, sizeof(dp)); dp[0] = 1; for (int i = 1, p; i <= n; i++) { p = 1; for (int j = i; j; j--) { if (trie[p][s[j] - 'a']) p = trie[p][s[j] - 'a']; else break; if (End[p]) { dp[i] += (dp[j - 1] * End[p]) % 20071027; dp[i] %= 20071027; } } } printf("Case %d: %d\n", cnt, dp[n]); } return 0; }