Bill的挑战
Time Limit: 4 Sec Memory Limit: 64 MB
Description
第一行:一个整数T,表示数据的个数。
对于每组数据:
第一行:两个整数,N和K(含义如题目表述)。
接下来N行:每行一个字符串。
Output
T行,每行一个整数表示答案
1
2 1
a?
?b
Sample Output
50
HINT
T ≤ 5,M ≤ 15,字符串长度≤ 50。
Solution
我们运用状压DP,令 g[i][c] 表示第 i 位,用 字符c 来匹配可行的串的集合。
然后显然就可以DP啦!f[i][opt] 表示做到了第 i 位,匹配集合为opt的方案数。
Code
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
| #include<bits/stdc++.h> using namespace std; typedef long long s64;
const int ONE = 4e5 + 5; const int MOD = 1000003;
int n, m, T; int g[52][52], f[52][32769]; char s[25][52]; int Ans;
int get() { int res=1,Q=1;char c; while( (c=getchar())<48 || c>57 ) if(c=='-')Q=-1; res=c-48; while( (c=getchar())>=48 && c<=57 ) res=res*10+c-48; return res*Q; }
void Deal() { memset(g, 0, sizeof(g)); memset(f, 0, sizeof(f)); n = get(); m = get(); for(int i = 1; i <= n; i++) scanf("%s", s[i] + 1);
int len = strlen(s[1] + 1); for(int i = 1; i <= len; i++) for(int c = 1; c <= 26; c++) for(int j = 1; j <= n; j++) if(s[j][i] == '?' || s[j][i] == c + 'a' - 1) g[i][c] |= 1 << j - 1;
int total = (1 << n) - 1; f[1][total] = 1; for(int i = 1; i <= len; i++) for(int opt = 0; opt <= total; opt++) if(f[i][opt]) for(int c = 1; c <= 26; c++) (f[i + 1][opt & g[i][c]] += f[i][opt]) %= MOD;
Ans = 0; for(int opt = 0; opt <= total; opt++) { int num = 0; for(int j = 1; j <= n; j++) if(opt & (1 << j - 1)) num++; if(num == m) Ans = (Ans + f[len + 1][opt]) % MOD; }
printf("%d\n", Ans); }
int main() { T = get(); while(T--) Deal(); }
|