[BZOJ1879] [Sdoi2009] Bill的挑戰 [狀態壓縮][dp]
阿新 • • 發佈:2018-11-12
觀察資料範圍考慮狀態壓縮?
考慮把字串匹配拆成每一位匹配,顯然可以每位求與遞推,到最後就是匹配狀態了。
陣列不要開小。
可以容斥。
#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;
}