题解 P2167 【[SDOI2009]Bill的挑战】
这是一个非常无脑的,本菜鸡上文化课时自己想到的弱智状压,结果是对的只是非常慢,看没有人用这种写法于是我就决定发一篇qwq
非常无脑!
设
然后假设我们有了
我们先开一个数组
比如
那么
发现,如果我们枚举
然后我们就可以快乐的转移了~
设
代码如下:
#include<bits/stdc++.h>
#define ljc 1000003
using namespace std;
inline int getit(){
//转化 a->1,b->2,...,z->26,?->27
char ch=getchar();
while (!isalpha(ch)&&(ch!='?')) ch=getchar();
if (isalpha(ch)) return ch-'a'+1;
else return 27;
}
inline int read(){
int x=0,f=1;char ch=getchar();
while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}
while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-48;ch=getchar();}
return x*f;
}
char s[10000];
int a[1600][5100],has[280][5100],len,T,n,m,f[51][33333];
inline int countbit(int x){
//返回二进制数x中有多少为1
int ans=0;
while (x){
if (x&1) ans++;
x>>=1;
}
return ans;
}
int main(){
T=read();
while (T--){
memset(f,-1,sizeof(f));
memset(has,0,sizeof(has));
n=read(),m=read();int ans=0;
scanf("%s",s);len=strlen(s);
for (int i=0;i<len;i++){
if (isalpha(s[i])) a[1][i+1]=s[i]-'a'+1;
else a[1][i+1]=27;
}
for (int i=2;i<=n;i++){
for (int j=1;j<=len;j++){
a[i][j]=getit();
}
}
f[0][(1<<n)-1]=1;
for (int i=0;i<len;i++){
for (int P=0;P<(1<<n);P++){//P就是上述的j状态qwq
if (f[i][P]==-1) continue;
for (int k=1;k<=26;k++) has[k][0]=0;//has[i][0]表示上述的size qwq
for (int j=1;j<=n;j++){
if ((P&(1<<j-1))==0) continue;
if (a[j][i+1]<=26) has[a[j][i+1]][++has[a[j][i+1]][0]]=j;
else{
for (int k=1;k<=26;k++) has[k][++has[k][0]]=j;
}
}
for (int j=1;j<=26;j++){
if (has[j][0]){
int rev=0;
for (int k=1;k<=has[j][0];k++) rev+=(1<<has[j][k]-1);
if (f[i+1][rev]==-1) f[i+1][rev]=0;
f[i+1][rev]=(f[i+1][rev]+f[i][P])%ljc;//转移
}
}
}
}
for (int P=0;P<(1<<n);P++){
if (f[len][P]==-1) continue;
if (countbit(P)==m) ans=(ans+f[len][P])%ljc;
}
cout<<ans<<endl;
}
return 0;
}