Solution - [SDOI2009] Bill的挑战

思路

一道简单状压 DP。

由数据范围可得大概率是状压或者爆搜,于是先考虑暴力构造然后判断。显然过不去。

于是开始状压。令 \(dp_{i,j}\) 为长度为 \(i\)、匹配情况为 \(j\) 的字符串个数,不难推出转移方程式。于是自动打表出“筛子”(位与的第二个参数)。

于是,没了。

代码

#include <bits/stdc++.h>
#define rint register int
#define rllong register long long
#define llong long long
#define N 16
#define M 55
#define mod 1000003
using namespace std;

#define setbit1(x,n) (x |= 1<<n-1)
#define setbit0(x,n) (x &= ~(1<<n-1))
#define getbit(x,n)  (x & (1<<n-1))
inline int popcnt(rint x){
	rint cnt = 0;
	while(x)
		cnt += x&1, x >>= 1;
	return cnt;
}

llong temp[M][26], dp[M][1<<N], ans;
char a[N][M];
int n, m, k;

inline int _main(){
	scanf("%d %d", &n, &k);
	for(rint i = 1; i <= n; ++i)
		scanf("%s", a[i]+1);
	m = strlen(a[1]+1);
	for(rint i = 1; i <= m; ++i)
		for(rint j = 0; j < 26; ++j)
			temp[i][j] = 0;
	for(rint i = 1; i <= m; ++i)
		for(rint j = 1; j <= n; ++j){
			if(a[j][i] == '?')
				for(rint k = 0; k < 26; ++k) setbit1(temp[i][k], j);
			else setbit1(temp[i][a[j][i]-'a'], j);
		}
	for(rint j = 0; j < 1<<n; ++j)
	    dp[1][j] = 0;
	for(rint i = 0; i < 26; ++i)
		++dp[1][temp[1][i]];
	for(rint i = 1; i < m; ++i){
		for(rint j = 0; j < 1<<n; ++j)
		    dp[i+1][j] = 0;
		for(rint j = 0; j < 1<<n; ++j)
			for(rint k = 0; k < 26; ++k)
				dp[i+1][j&temp[i+1][k]] = (dp[i+1][j&temp[i+1][k]]+dp[i][j])%mod;
	}
	ans = 0;
	for(rint j = 0; j < 1<<n; ++j)
	    if(popcnt(j) == k) ans = (ans+dp[m][j])%mod;
	printf("%lld\n", ans);
	return 0;
}

int t;
int main(){
	scanf("%d", &t);
	while(t--) _main();
	return 0;
}

posted @ 2025-04-23 16:49  Hootime  阅读(21)  评论(0)    收藏  举报