看数据范围发现n异常的小,于是想到装压
map[i][j]表示第i个字符填j时与那些匹配串符合
dp[i][j] 表示第i个字符,匹配的情况为j,有多少方案
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#define gi get_int()
const int MAXN = 60, LIM = 1 << 16;
int get_int()
{
int x = 0, y = 1;
char ch = getchar();
while (!isdigit(ch) && ch != '-')
ch = getchar();
if (ch == '-')
y = -1, ch = getchar();
while (isdigit(ch))
x = x * 10 + ch - '0', ch = getchar();
return x * y;
}
int map[MAXN][26], dp[2][LIM];
int countBit(int x)
{
int ans = 0;
while (x != 0) {
ans += x & 1;
x >>= 1;
}
return ans;
}
int main()
{
freopen("code.in", "r", stdin);
freopen("code.out", "w", stdout);
int T = gi;
while (T--) {
memset(dp, 0, sizeof(dp));
memset(map, 0, sizeof(map));
int n = gi, k = gi, size;
for (int i = 0; i < n; i++) {
std::string str;
std::cin >> str;
size = str.size();
for (int j = 0; j < size; j++) {
if (str[j] == '?')
for (int k = 0; k < 26; k++)
map[j][k] |= 1 << i;
else
map[j][str[j] - 'a'] |= 1 << i;
}
}
for (int i = 0; i < 26; i++) {
dp[0][map[0][i]]++;
}
for (int i = 0; i < size - 1; i++) {
for (int j = 0; j < (1 << n); j++) {
for (int k = 0; k < 26; k++)
dp[!(i & 1)][j] = 0;
}
for (int j = 0; j < (1 << n); j++) {
for (int k = 0; k < 26; k++)
(dp[!(i & 1)][j & map[i + 1][k]] += dp[i & 1][j]) %= 1000003;
}
}
int ans = 0;
for (int i = 0; i < (1 << n); i++) {
if (countBit(i) == k)
(ans += dp[1 & (size - 1)][i]) %= 1000003;
}
std::cout << ans << std::endl;
}
return 0;
}