返回顶部

Bill的挑战

[SDOI2009] Bill的挑战

题目描述

Sheng_bill 不仅有惊人的心算能力,还可以轻松地完成各种统计。在昨天的比赛中,你凭借优秀的程序与他打成了平局,这导致 Sheng_bill 极度的不满。于是他再次挑战你。这次你可不能输。

这次,比赛规则是这样的:

给出 \(N\) 个长度相同的字符串(由小写英文字母和 ? 组成),\(S_1,S_2,\dots,S_N\),求与这 \(N\) 个串中的刚好 \(K\) 个串匹配的字符串 \(T\) 的个数,答案对 \(1000003\) 取模。

若字符串 \(S_x(1\le x\le N)\)\(T\) 匹配,满足以下条件:

  1. \(|S_x|=|T|\)
  2. 对于任意的 \(1\le i\le|S_x|\),满足 \(S_x[i]= \texttt{?}\) 或者 \(S_x[i]=T[i]\)

其中 \(T\) 只包含小写英文字母。

输入格式

本题包含多组数据

第一行一个整数 \(T\),表示数据组数。

对于每组数据,第一行两个整数,\(N\)\(K\)

接下来 \(N\) 行,每行一个字符串 \(S_i\)

输出格式

每组数据输出一行一个整数,表示答案。

样例 #1

样例输入 #1

5
3 3
???r???
???????
???????
3 4
???????
?????a?
???????
3 3
???????
?a??j??
????aa?
3 2
a??????
???????
???????
3 2
???????
???a???
????a??

样例输出 #1

914852
0
0
871234
67018

提示

数据规模与约定

  • 对于 \(30\%\) 的数据,\(N\le5\)\(|S_i|\le20\)
  • 对于 \(70\%\) 的数据,\(N\le13\)\(|S_i|\le30\)
  • 对于 \(100\%\) 的数据,\(1\le T\le 5\)\(1\le N \le15\)\(1\le|S_i|\le50\)

这题,肯定状压DP
但是长度<=50故我们必须换一种思路,状态压缩N个字符串匹配状态
\(我们定义f[i][j]为T串已经匹配了i位,且与n个字符串是否匹配的集合为j\)
然后预处理出T每一位上从[a~z]的情况下与N个字符串的匹配情况
然后动态转移方程为
\(F[i][j\And ac[i][k]]=f[i][j\And ac[i][k]]+f[i-1][j]\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
const int N =1005,mod=1000003;
void T(int x){bitset<10> a;a=x;cout<<a<<endl;}
int t,n,k,f[55][(1<<15)+5],AC[55][30];
string s[20];
int main()
{
	ios_base::sync_with_stdio(false);
	cin.tie(0);cout.tie(0);	
	cin>>t;
	while(t--)
	{
		cin>>n>>k;
		for(int i=1;i<=n;i++)
		{
			s[i].clear();
			cin>>s[i];
		}
		if(k>n)
		{
			cout<<0<<endl;
			continue;
		}
		int len=s[1].size();
		memset(f,0,sizeof(f));
		memset(AC,0,sizeof(AC));
		for(int i=0;i<len;i++)
		{
			for(char ch='a';ch<='z';ch++)
			{
				for(int k=1;k<=n;k++)
				{
					if(s[k][i]=='?'||s[k][i]==ch)
					{
						AC[i][ch-'a']|=(1<<(k-1));
					}
				}
			}
		}
		f[0][(1<<n)-1]=1;
		for(int i=0;i<len;i++)
		{
			for(int j=0;j<(1<<n);j++)
			{
				if(f[i][j])
				for(int k=0;k<26;k++)
				{
					f[i+1][j&AC[i][k]]=(f[i+1][j&AC[i][k]]+f[i][j])%mod;
				}
			}
		}
		int ans=0;
		for(int i=0;i<(1<<n);i++)
		{
			int tot=0;
			for(int j=0;j<n;j++)
			{
				if(i&(1<<j))tot++;
			}
			if(tot==k)ans=(ans+f[len][i])%mod;
		}
		cout<<ans<<endl;
	}
	return 0;
}

posted @ 2024-04-09 12:11  wlesq  阅读(7)  评论(0编辑  收藏  举报