Bzoj1879 [Sdoi2009]Bill的挑战
Submit: 724 Solved: 363
Description
Input
本题包含多组数据。 第一行:一个整数T,表示数据的个数。 对于每组数据: 第一行:两个整数,N和K(含义如题目表述)。 接下来N行:每行一个字符串。
Output
1
2 1
a?
?b
Sample Input
50
Sample Output
对于30%的数据,T ≤ 5,N ≤ 5,字符串长度≤ 20;
对于70%的数据,T ≤ 5,N ≤ 13,字符串长度≤ 30;
对于100%的数据,T ≤ 5,N ≤ 15,字符串长度≤ 50。
对于70%的数据,T ≤ 5,N ≤ 13,字符串长度≤ 30;
对于100%的数据,T ≤ 5,N ≤ 15,字符串长度≤ 50。
HINT
Source
动规 状压DP
这题简直思路清奇。
刚开始想的是预处理出每两个串之间能否匹配,以及每个串能匹配它之前出现的多少串,然后DP。←想来好复杂,而且可能还要容斥,那就是超复杂了。
(说不定也能强行做出来呢 http://www.cnblogs.com/SilverNebula/p/6001294.html)
再一看数据范围,啊,状压你好。
所有串的长度一样,所以可以统一处理,预处理g[i][j]=x表示字符j可以和x集合内的串的第i位匹配
f[匹配长度][集合]=方案数
f[0][全满集合]=1
f[i][ k&g[i-1][j] ]+=f[递推位数i-1][枚举集合k]
1 /*by SilverN*/ 2 #include<algorithm> 3 #include<iostream> 4 #include<cstring> 5 #include<cstdio> 6 #include<cmath> 7 #include<vector> 8 using namespace std; 9 const int mod=1e6+3; 10 const int mxn=100010; 11 int f[51][1<<15]; 12 int g[51][27]; 13 char s[16][52]; 14 int T,n,K; 15 int main(){ 16 int i,j; 17 scanf("%d",&T); 18 while(T--){ 19 memset(f,0,sizeof f); 20 scanf("%d%d",&n,&K); 21 for(i=0;i<n;i++){scanf("%s",s[i]);} 22 int len=strlen(s[0]); 23 for(i=0;i<len;i++)//长度 24 for(int k=0;k<26;k++){//字母 25 g[i][k]=0; 26 for(j=0;j<n;j++){//串 27 if(s[j][i]=='?' || s[j][i]==k+'a')g[i][k]|=(1<<j); 28 } 29 } 30 int ed=(1<<n)-1; 31 f[0][ed]=1; 32 for(i=1;i<=len;i++){ 33 for(int k=0;k<=ed;k++){ 34 if(f[i-1][k]) 35 for(j=0;j<26;j++){ 36 (f[i][k&g[i-1][j]]+=f[i-1][k])%=mod; 37 } 38 } 39 } 40 int ans=0; 41 for(int k=0;k<=ed;k++){ 42 int tmp=k,cnt=0; 43 while(tmp){ 44 cnt++; 45 tmp-=tmp&-tmp; 46 } 47 if(cnt==K)ans=(ans+f[len][k])%mod; 48 } 49 printf("%d\n",ans); 50 } 51 return 0; 52 }
本文为博主原创文章,转载请注明出处。