洛谷 P2167 [SDOI2009] Bill的挑战
像这种字符串匹配的题,状态设计里一定有一维代表目前匹配到了第。只需要枚举所有状态,然后看看有哪些状态中。位的字符串中,还有哪些可以匹配上第。的可能的字符,然后看看有哪些。的意思就是,当前已经匹配第。假设能匹配的字符串的状态为。,我们就枚举下一个位置。,那么我们就可以转移。,转移不到下一个状态。
题目传送门
思路
状态设计
像这种字符串匹配的题,状态设计里一定有一维代表目前匹配到了第 i i i 位。
所以,我们设 d p i , j dp_{i, j} dpi,j 表示目前 T T T 串已经匹配到了第 i i i 位,且匹配的 S S S 串的状态为 j j j。
状态转移
假设现在状态为 j j j,我们就枚举下一个位置 T i + 1 T_{i + 1} Ti+1 的可能的字符,然后看看有哪些 S S S 串能匹配上。
假设能匹配的字符串的状态为 x x x,那么我们就可以转移 d p i + 1 , j & x + = d p i , j dp_{i + 1, j \ \& \ x} += dp_{i, j} dpi+1,j & x+=dpi,j。
这里 j & x j \ \& \ x j & x 的意思就是,当前已经匹配第 i i i 位的字符串中,还有哪些可以匹配上第 i + 1 i + 1 i+1 位。
边界状态
边界状态是 d p 0 , 2 n − 1 = 1 dp_{0, 2 ^ n - 1} = 1 dp0,2n−1=1。
那么为什么边界不是 d p 0 , 0 = 1 dp_{0, 0} = 1 dp0,0=1 呢?
因为如果由 0 0 0 作为初始状态的话 0 & x 0 \ \& \ x 0 & x 会一直为 0 0 0,转移不到下一个状态。
答案统计
只需要枚举所有状态,然后看看有哪些状态中 1 1 1 的个数恰好为 k k k,那就加入答案
时间复杂度
O ( T × 26 × 2 n × ∣ S ∣ ) O(T \times 26 \times 2 ^ n \times |S|) O(T×26×2n×∣S∣)
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn = 15 + 7;
const int maxs = (1 << 15) + 7;
const int mod = 1000003;
int T, n, m, ns, len;
char s[maxn][57];
int mch[57][30];
int dp[57][maxs];
void solve() {
memset(mch, 0, sizeof(mch));
memset(dp, -1, sizeof(dp)); // 初始化成 -1, 因为一些状态可能转移不到
scanf("%d%d", &n, &m);
ns = (1 << n) - 1;
for (int i = 1; i <= n; ++i)
scanf("%s", s[i] + 1);
len = strlen(s[1] + 1);
// 初始化一下, 看看第 i 位的字符为 ch 时能匹配的 S 串的状态
for (int i = 1; i <= len; ++i)
for (int ch = 1; ch <= 26; ++ch)
for (int j = 1; j <= n; ++j)
if (s[j][i] - 'a' + 1 == ch || s[j][i] == '?')
mch[i][ch] |= 1 << (j - 1);
dp[0][ns] = 1;
for (int i = 0; i < len; ++i) {
for (int s = 0; s <= ns; ++s) {
if (dp[i][s] == -1) continue;
for (int ch = 1; ch <= 26; ++ch) {
int nxt = (s & mch[i + 1][ch]);
if (dp[i + 1][nxt] == -1) dp[i + 1][nxt] = 0;
dp[i + 1][nxt] = (dp[i + 1][nxt] + dp[i][s]) % mod;
}
}
}
int ans = 0;
for (int s = 0; s <= ns; ++s) {
int cntbit = 0;
for (int i = 0; i < n; ++i)
if (s & (1 << i)) ++cntbit;
if (cntbit == m && dp[len][s] != -1)
ans = (ans + dp[len][s]) % mod;
}
printf("%d\n", ans);
}
int main() {
scanf("%d", &T);
while (T--) solve();
return 0;
}
更多推荐
所有评论(0)