返回顶部

Bill的挑战

看数据范围就知道应该要状压,也不难看出应该压缩位数的状态。所以设f[i][j]为前i位,相互匹配的字符串的状态。

那么,就会有

\[{f^i_{(j \bigcap a^i_{ch})} }=(f^{i+1}_{(j\bigcap a^i_{ch})}+f^i_j ) mod (p) \]

其中a[i][j]表示满足第i位为j所对应的字母的字符串的状态。

所以只要枚举长度为l(其中一个字符串的长度)时的状态,并检查一下当前状态下匹配的字符串的个数是否为k,再更新答案。

点击查看代码
using namespace std;
const int N=16,M=51;
#define mod 1000003
int n,m,k,i,j,T,ans,f[M][(1<<N)],a[M][26];
//a[i][j]代表第i位为字母j+'0'的字符串的集合(状态);
//f[i][j]表示前i位,相互匹配的字符串的集合;
string s[N];
int main(){
    scanf("%d",&T);
    while(T--){
        ans=0;
        memset(f,0,sizeof f);
        memset(a,0,sizeof a);
        scanf("%d%d",&n,&k);
        for(i=1;i<=n;i++)cin>>s[i];
        int l=s[1].length();
        for(i=0;i<l;i++){
            for(char ch='a';ch<='z';ch++){
                for(j=1;j<=n;j++){
                    if(s[j][i]=='?'||s[j][i]==ch)
                        a[i][ch-'a']|=(1<<j-1);
                }
            }
        }
        f[0][(1<<n)-1]=1;
        for(i=0;i<l;i++){
            for(j=0;j<(1<<n);j++){
                if(f[i][j]){
                    for(char ch='a';ch<='z';ch++){
                        f[i+1][(j&a[i][ch-'a'])]=(f[i+1][(j&a[i][ch-'a'])]+f[i][j])%mod;
                    }
                }
            }
        }
        for(i=0;i<(1<<n);i++){
            int tot=0;
            for(j=1;j<(1<<n);j<<=1)if(i&j)if(++tot>k)break;
            if(tot==k)ans=(ans+f[l][i])%mod;
        }
        printf("%d\n",ans);
    }
    return 0;
}
posted @ 2024-04-08 21:31  无敌の暗黑魔王  阅读(9)  评论(0编辑  收藏  举报