CSES Word Combination(字典树,DP)
题意
给定一个字符串s, 给$n$个单词, 问:
这个字符串可以被这些单词组合成多少种方式?
题解
使用dp思想解决有多少种组合, 使用trie来快速匹配单词
- 定义状态
dp[i]表示前i个字符可以被这些单词组合成多少种方式
- 初始化
dp[0] = 1
- 状态转移: 如果
dp[i] != 0说明有以第i个字符结尾的单词, 那么就查找可以从i之后出发的单词在i+1到j之间, 那么dp[j+1] = (dp[j+1] + dp[i]) % M;
- 返回
dp[s.size()]
code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
| #pragma GCC optimize("Ofast") #include<bits/stdc++.h> using namespace std; #define i128 __int128
#define DEBUG #ifdef DEBUG #define de(x) cout << (#x) << " = " << (x) << endl; #define de2(x, y) cout << (#x) << " , " << (#y) << " = " << (x) << " ~ " << (y) << endl; #else #define de(x) #define de2(x, y) #endif #define enld endl #define endl '\n' #define fi(x) for(int i = 1; i <= x; ++i) #define fi0(x) for(int i = 0; i < x; ++i) #define fj(n) for(int j = 1; j <= n; ++j) #define caillo ios::sync_with_stdio(0);cin.tie(0);cout.tie(0); #define PLEASE_AC return 0 typedef long long ll; typedef unsigned long long ull;
const int N = 1e6 + 10; const int M = 1e9 + 7; int node[N][26], idx; bool isEnd[N];
void insert(const string &s) { int p = 0; for(int i = 0; i < s.size(); ++i) { int ch = s[i] - 'a'; if(!node[p][ch]) node[p][ch] = ++idx; p = node[p][ch]; } isEnd[p] = true; }
int dp[N]; signed main() { caillo; string s; cin >> s; int n; cin >> n; fi(n) { string t; cin >> t; insert(t); }
dp[0] = 1; for(int i = 0;i < s.size(); ++i) { if(!dp[i]) continue; int p = 0; for(int j = i;j < s.size(); ++j) { int ch = s[j] - 'a'; if(!node[p][ch]) break;
p = node[p][ch]; if(isEnd[p]) dp[j+1] = (dp[j+1] + dp[i]) % M; } }
cout << dp[s.size()] << endl; }
|