BZOJ1879_Bill的挑战_KEY
第一次看题目感觉毫无还手之力,一看M的范围≤15,果断状压。
但是状压的想法比较新奇。
先想到的状压是设f[i][j]表示前i个状态为j时的方案总数,但是后来想了一想不行,会超时。
于是以f[i][j]表示i状态匹配到第j位时的方案总数。
但判断转移是会超时,于是预处理串与串之间的关系。
设g[i][j]表示第i位(字符串)为字母j时有多少串符合。
f转移时直接&g数组就好了。
code:
/************************************************************** Problem: 1879 User: yekehe Language: C++ Result: Accepted Time:804 ms Memory:7820 kb ****************************************************************/ #include <cstdio> #include <string> #include <cstring> #include <iostream> using namespace std; const int mod=1000003; int T,N,K,f[1<<15][51],g[51][26]; string S[55]; int main() { // freopen("x.txt","r",stdin); scanf("%d",&T); register int i,j,k; while(T--){ scanf("%d%d\n",&N,&K); memset(f,0,sizeof f); memset(g,0,sizeof g); for(i=1;i<=N;i++)cin>>S[i]; int len=S[1].size(); for(i=0;i<len;i++){ for(j=0;j<26;j++) for(k=1;k<=N;k++) if(S[k][i]=='?' || S[k][i]==(j+'a')) g[i][j]|=1<<k-1; } f[(1<<N)-1][0]=1; for(i=0;i<len;i++){ for(j=0;j<1<<N;j++){ if(f[j][i])//这里注意要判断,不然会因为%的常数太大而超时。 for(k=0;k<26;k++){ f[j&g[i][k]][i+1]=(f[j&g[i][k]][i+1]+f[j][i])%mod; } } } int ans=0; for(i=0;i<1<<N;i++){ j=i,k=0; while(j){k+=j&1;j>>=1;} if(k==K)ans=(ans+f[i][len])%mod; } printf("%d\n",ans); } return 0; }