一道字符串&DP好题。
题意
给你一个字符串 s,还有 k 组字符串,问你从每组字符串中只选一个字符串,且按顺序排列后连接起来的串为 s 的子串的选择种数有多少个,对 1e9+7 取模。
题解
显然是道 DP。
定义 fi,j 表示按顺序选到第 i 组串且连接起来的字符串匹配到 s 的第 j 个位置的种数。
显然不是每个状态都能转移到 fi,j。当且仅当第 i 组中的某个字符串被 s 从 j 结尾的最后几个字符匹配才能转移,这样就好办了。
用哈希判断就可以了,也可以用 KMP,但我觉得哈希对于这题来说更简单。
代码
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
| #include <cstdio> #include <iostream>
using namespace std;
typedef unsigned long long ULL;
const int N = 1e4 + 5; const int K = 1e2 + 5; const int MOD = 1e9 + 7; const int BASE = 13331;
string s, a[K][15]; int k, n, c[K], f[K][N]; ULL hs[N], hsh[K][15], pw[N];
void Prework () { pw[0] = 1; for (int i = 1; i <= n; ++i) pw[i] = pw[i - 1] * BASE; hs[0] = s[0]; for (int i = 1; i < n; ++i) hs[i] = hs[i - 1] * BASE + s[i];
}
ULL Gethsh (int l, int r) { if (!l) return hs[r]; return hs[r] - hs[l - 1] * pw[r - l + 1]; }
int main() { cin >> k >> s; n = s.size(); for (int i = 1; i <= k; ++i) { cin >> c[i]; for (int j = 1; j <= c[i]; ++j) { cin >> a[i][j]; int len = a[i][j].size(); for (int s = 0; s < len; ++s) hsh[i][j] = hsh[i][j] * BASE + a[i][j][s];
} } Prework(); for (int i = 0; i < n; ++i) f[0][i] = 1; for (int i = 1; i <= k; ++i) for (int j = 1; j <= c[i]; ++j) { int len = a[i][j].size();
for (int s = len - 1; s < n; ++s) { f[i][s + 1] = (f[i][s + 1] + (hsh[i][j] == Gethsh(s - len + 1, s)) * f[i - 1][s - len + 1]) % MOD;
} } int ans = 0; for (int i = 0; i < n; ++i) ans = (ans + f[k][i + 1]) % MOD; cout << ans << endl; return 0; }
|