您的位置:首页 > 其它

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

2016-02-29 11:19 615 查看
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]

【代码】

#include<cstdio>
#include<cstring>
using namespace std;

const int N = 16 , M = 55;
const int MOD = 1e6+3;

int f[M][1<<N],g[M][26];
char s
[M];

int T,n,K,len;

int main() {
scanf("%d",&T);
while(T--) {
memset(f,0,sizeof(f));
memset(g,0,sizeof(g));
scanf("%d%d",&n,&K);
for(int i=0;i<n;i++)
scanf("%s",s[i]);
len=strlen(s[0]);
for(int i=0;i<len;i++)
for(int j=0;j<n;j++) {
if(s[j][i]!='?')
g[i][s[j][i]-'a']^=(1<<j);
else
for(int k=0;k<26;k++)
g[i][k]^=(1<<j);
}
int all=1<<n; f[0][all-1]=1;
for(int i=0;i<len;i++)
for(int j=0;j<all;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,cnt;
for(int j=0;j<all;j++) {
cnt=0;
for(int i=0;i<n;i++)
if(j&(1<<i)) cnt++;
if(cnt==K) ans=(ans+f[len][j])%MOD;
}
printf("%d\n",ans);
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: