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;
}

浙公网安备 33010602011771号