【题解】[SDOI2009]Bill的挑战

[SDOI2009]Bill的挑战

\(\text{Solution:}\)

最初的 naive 想法是直接枚举子集算出每个子集中全部匹配的对应 \(T\) 串的个数,但是脑残到最后写完才反应过来会算重……

但好像用二项式反演还能搞回来(雾)

考虑 dp : 设 \(dp[i][j]\) 表示填充好 \([1,i]\) 的长度,能匹配的子集状态是 \(j\) 的方案数。

那么可以考虑用刷表法,枚举 \(i+1\) 位置填什么。一共 \(26\) 种组合。所以可以预处理出 \(i\) 位置能匹配字符 \(j\) 的状态集合,转移就可以是:

\[\text{dp[i+1][j&state]+=dp[i][j]} \]

就是对能匹配的集合求交集。

于是这样的方案数一定是不重复的,因为每一次填上位置的字符都不同。

不是说匹配到的字符串不同,而是我们自己构造出的 \(T\) 是不同的。

重点在于让你每次构造出来的 \(T\) 都是不同的,这样才会保证不重不漏。

从这角度出发,进而启发我们对字符串 \(T\) 进行 \(dp\),状态是和 \(T\) 息息相关的。

重点在于要反思设计状态后注意一定不能把状态给算重复了,一定要考虑最容易算重的是什么。

这个时候往往可以考虑一下状态对它设计,这样更有利于我们对它去重计数的处理。

傻逼错误:数组开小了,调了半天,下次写代码就直接把数组拉到最不可能出错的大小就行了。

#include<bits/stdc++.h>
using namespace std;
const int mod=1000003;
inline int Mod(int x) {
	return (x>=mod?(x-mod):(x<0?(x+mod):x));
}
inline int Max(int x,int y) {
	return x>y?x:y;
}
inline int Min(int x,int y) {
	return x<y?x:y;
}
inline int Add(int x,int y) {
	return Mod(x+y);
}
inline int Mul(int x,int y) {
	return 1ll*Mod(x)*Mod(y)%mod;
}
int T,n,dp[51][1<<17],len,K;
int match[51][26];
char A[17][60];
inline int pop_count(int x) {
	int res=0;
	while(x!=0) {
		res+=x&1;
		x>>=1;
	}
	return res;
}
inline void Clear() {
	memset(dp,0,sizeof dp);
	memset(match,0,sizeof match);
}
int main() {
	freopen("111.txt","r",stdin);
	scanf("%d",&T);
	while(T--) {
		scanf("%d%d",&n,&K);
		Clear();
		for(int i=1; i<=n; ++i) {
			scanf("%s",A[i]+1);
		}
		len=strlen(A[1]+1);
		int w=(1<<n)-1;
		dp[0][w]=1;
		for(int i=1; i<=len; ++i) {
			for(int j=0; j<26; j++) {
				for(int k=1; k<=n; k++) {
					if(A[k][i]=='?'||A[k][i]-'a'==j) {
						match[i][j]|=(1<<(k-1));
					}
				}
			}
		}
		for(int i=0; i<len; ++i) {
			for(int j=0; j<(1<<n); ++j) {
				for(int k=0; k<26; ++k) {
					int state=j&match[i+1][k];
					dp[i+1][state]+=dp[i][j];
					if(dp[i+1][state]>=mod)dp[i+1][state]-=mod;
				}
			}
		}
		int ans=0;
		for(int i=0; i<(1<<n); ++i) {
			if(__builtin_popcount(i)==K) {
				ans=ans+dp[len][i];
				if(ans>=mod)ans-=mod;
			}
		}
		cout<<ans<<endl;
	}
	return 0;
}
posted @ 2021-07-12 16:40  Refined_heart  阅读(69)  评论(0编辑  收藏  举报