bzoj1879 SDOI2009]Bill的挑战 (状压dp)

Problem

n n n 个模式串,能匹配其中 k k k 个的字符串的个数
匹配的含义为 若为 “?” 则与所以字母都匹配,若为字母,则需相同

Solution

首先看的 n n n 很小,然后可能使用状压 d p dp dp 来解决

a [ i ] [ j ] a[i][j] a[i][j] 表示第 i i i 位这 n n n 个模式串在这一位是 ′ a ′ 'a' a+ j j j 的程度

f [ i ] [ j ] f[i][j] f[i][j] 表示到第 i i i 位的能匹配的个数

f [ i + 1 ] [ j f[i+1][j f[i+1][j & \& & a [ i ] [ k ] ] + = f [ i ] [ j ] a[i][k]]+=f[i][j] a[i][k]]+=f[i][j]

注:x-=x&-x 更快诶

Code

#include 
#include 
#define mod 1000003
#define N 70000
int n,m,T,len;
int f[55][N],a[55][30];
char str[55];
int main(){
	freopen("a.in","r",stdin);
	scanf("%d",&T);
	while(T--){
		scanf("%d%d",&n,&m);
		memset(a,0,sizeof(a));
		for(int i=1;i<=n;i++){
			scanf("%s",str+1);
			len=strlen(str+1);
			for(int j=1;j<=len;j++)
				for(int k=0;k<26;k++){
					if(str[j]=='?' || str[j]=='a'+k) a[j][k]|=1<<(i-1);
				}
		}
		int lim=(1<<n)-1;
		memset(f,0,sizeof(f));
		for(int i=0;i<26;i++) f[1][a[1][i]]+=1;
		for(int i=1;i<len;i++){
			for(int j=0;j<=lim;j++)
				if(f[i][j]){
					for(int k=0;k<26;k++){
						(f[i+1][j&a[i+1][k]]+=f[i][j])%=mod;
					}
				}
		}
		int ans=0;
		for(int i=1;i<=lim;i++){
			int x=i,cnt=0;
			while(x){
//				if(x&1) 
				cnt++;
//				x>>=1;
				x-=x&-x;
			}
				if(cnt==m) {(ans+=f[len][i])%=mod;}
		}
		printf("%d\n",ans);
	}
	return 0;
}

你可能感兴趣的:(状压dp,dp)