Bill的挑战(bzoj 1879)

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][j]为T串已经匹配了i位,且与n个字符串是否匹配的集合为j
  为了方便转移,设g[i][j]为第i个字母是j的可匹配集合。 
*/
#include<cstdio>
#include<cstring>
#include<iostream>
#define mod 1000003
using namespace std;
char s[20][60];
int g[60][30],f[60][33000],n,k;
void work(){
    scanf("%d%d",&n,&k);
    for(int i=0;i<n;i++)
        scanf("%s",s[i]);
    int len=strlen(s[1]);
    for(int i=0;i<len;i++)
        for(int j=0;j<26;j++)
            for(int k=0;k<n;k++)
                if(s[k][i]=='?'||s[k][i]==j+'a')
                    g[i][j]|=(1<<k);
    int N=1<<n;f[0][N-1]=1;
    for(int i=0;i<len;i++)
        for(int j=0;j<N;j++)
            if(f[i][j])
                for(int k=0;k<26;k++)
                    f[i+1][j&g[i][k]]=(f[i+1][j&g[i][k]]+f[i][j])%mod;
    int ans=0;
    for(int j=0;j<N;j++){
        int tot=0;
        for(int p=0;p<n;p++)
            if(j&(1<<p))tot++;
        if(tot==k)ans=(ans+f[len][j])%mod;
    }
    printf("%d\n",ans);
}
int main(){
    int T;scanf("%d",&T);
    while(T--){
        memset(f,0,sizeof(f));
        memset(g,0,sizeof(g));
        work();
    }
    return 0;
}

 

posted @ 2017-01-06 21:38  karles~  阅读(294)  评论(0编辑  收藏  举报