1. 程式人生 > >[BZOJ1879] [Sdoi2009] Bill的挑戰 [狀態壓縮][dp]

[BZOJ1879] [Sdoi2009] Bill的挑戰 [狀態壓縮][dp]

[ L i n k \frak{Link} ]


觀察資料範圍考慮狀態壓縮?
考慮把字串匹配拆成每一位匹配,顯然可以每位求與遞推,到最後就是匹配狀態了。
陣列不要開小。

p s . \frak{ps.} 可以容斥


#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include
<cmath>
#include<cctype> #include<cstdlib> #include<queue> using namespace std; const int mod = 1000003; int T, n, k, m; int a[100][100]; int f[100][50000]; char s[1000][1000]; int main() { scanf("%d", &T); while (T--) { scanf("%d%d", &n, &k); memset(s, 0, sizeof(s)); for (int i =
1; i <= n; ++i) { scanf(" %s", s[i]); } m = strlen(s[1]); for (int i = 0; i < m; ++i) { for (int j = 0; j < 26; ++j) { a[i][j] = 0; for (int k = 1; k <= n; ++k) { if (j + 'a' == s[k][i] || s[k][i] == '?') a[i][j] |= 1 << k - 1; } } } int up = (1 << n) - 1; memset(f, 0, sizeof(f)); f[0][up] = 1; //* 不能寫f[0][0] = 1 for (int i = 0; i < m; ++i) { for (int j = 0; j <= up; ++j) { if (!f[i][j]) continue; for (int k = 0; k < 26; ++k) { f[i+1][j&a[i][k]] += f[i][j]; f[i+1][j&a[i][k]] %= mod; } } } int ans(0); for (int j = 0; j <= up; ++j) { // * int cnt(0), t = j; while (t) { t ^= t & -t; ++cnt; } if (cnt == k) ans += f[m][j], ans %= mod; } printf("%d\n", ans); } return 0; }