bzoj 1879 [Sdoi2009]Bill的挑战(状压DP)

 

Description 

Input

本题包含多组数据。 第一行:一个整数T,表示数据的个数。 对于每组数据: 第一行:两个整数,N和K(含义如题目表述)。 接下来N行:每行一个字符串。 
Output

1 2 1 a? ?b 
Sample Input

50 
Sample Output

对于30%的数据,T ≤ 5,M ≤ 5,字符串长度≤ 20;

对于70%的数据,T ≤ 5,M ≤ 13,字符串长度≤ 30;

对于100%的数据,T ≤ 5,M ≤ 15,字符串长度≤ 50。 

 

【思路】

 

       状压DP

       f[i][s]表示前i-1个已经匹配,且匹配集合为s时的方案数。预处理出g[i][j]表示长度为i-1且最后一个字符为j的字符串集合。则有转移方程如下:      

              f[i+1][s&g[i][k]]+=f[i][j]

 

【代码】

 

 1 #include<cstdio>
 2 #include<cstring>
 3 using namespace std;
 4 
 5 const int N = 16 , M = 55;
 6 const int MOD = 1e6+3;
 7 
 8 int f[M][1<<N],g[M][26];
 9 char s[N][M];
10 
11 int T,n,K,len;
12 
13 int main() {
14     scanf("%d",&T);
15     while(T--) {
16         memset(f,0,sizeof(f));
17         memset(g,0,sizeof(g));
18         scanf("%d%d",&n,&K);
19         for(int i=0;i<n;i++)
20             scanf("%s",s[i]);
21         len=strlen(s[0]);
22         for(int i=0;i<len;i++)
23             for(int j=0;j<n;j++) {
24                 if(s[j][i]!='?')
25                     g[i][s[j][i]-'a']^=(1<<j);
26                 else
27                     for(int k=0;k<26;k++)
28                         g[i][k]^=(1<<j);
29             }
30         int all=1<<n; f[0][all-1]=1;
31         for(int i=0;i<len;i++)
32             for(int j=0;j<all;j++) if(f[i][j])
33                 for(int k=0;k<26;k++)
34                     f[i+1][j&g[i][k]]=(f[i+1][j&g[i][k]]+f[i][j])%MOD;
35         int ans=0,cnt;
36         for(int j=0;j<all;j++) {
37             cnt=0;
38             for(int i=0;i<n;i++)
39                 if(j&(1<<i)) cnt++;
40             if(cnt==K) ans=(ans+f[len][j])%MOD;
41         }
42         printf("%d\n",ans);
43     }
44     return 0;
45 }

 

 

你可能感兴趣的:(bzoj 1879 [Sdoi2009]Bill的挑战(状压DP))