P2167 [SDOI2009]Bill的挑战
Posted Jozky86
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了P2167 [SDOI2009]Bill的挑战相关的知识,希望对你有一定的参考价值。
题意:
有n个长度一样的字符串,字符串的每一位是?或者确定的字母,,求与这 N 个串中的刚好 K 个串匹配的字符串 T 的个数
1<=N<=15,1<=|S|<=50
题解:
很明显状态dp
我们可以先预处理一个match[1…len][a…z]:表示第i位取ch的状态,比如match[1]['a]=10101就表示第一个,第三个,第五个字符串的第一位可以取’a‘。预处理出match
f[i][j]表示第i位的匹配上了j这个状态的方案数
转移方程:
j=1010(二进制)就表示:选了第2行和第四行的字符串的状态
选在第i+1行时,要与第i行的状态取&
int now= (match[i][ch - 'a'] & j);
f[i + 1][now]= (f[i + 1][now] + f[i][j]) % mod;
最后枚举答案时,因为题目有说时选取k行,所以枚举所有状态,只有状态中带有k个1的是我们要的状态
代码:
// Problem: P2167 [SDOI2009]Bill的挑战
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P2167
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// Data:2021-08-11 21:21:14
// By Jozky
#include <bits/stdc++.h>
#include <unordered_map>
#define debug(a, b) printf("%s = %d\\n", a, b);
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> PII;
clock_t startTime, endTime;
//Fe~Jozky
const ll INF_ll= 1e18;
const int INF_int= 0x3f3f3f3f;
template <typename T> inline void read(T& x)
{
T f= 1;
x= 0;
char ch= getchar();
while (0 == isdigit(ch)) {
if (ch == '-')
f= -1;
ch= getchar();
}
while (0 != isdigit(ch))
x= (x << 1) + (x << 3) + ch - '0', ch= getchar();
x*= f;
}
template <typename T> inline void write(T x)
{
if (x < 0) {
x= ~(x - 1);
putchar('-');
}
if (x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
void rd_test()
{
#ifdef ONLINE_JUDGE
#else
startTime= clock();
freopen("in.txt", "r", stdin);
#endif
}
void Time_test()
{
#ifdef ONLINE_JUDGE
#else
endTime= clock();
printf("\\nRun Time:%lfs\\n", (double)(endTime - startTime) / CLOCKS_PER_SEC);
#endif
}
const int maxn= 100;
char s[maxn][maxn];
const int mod= 1e6 + 3;
int f[60][1 << 15];
int match[60][60];
int main()
{
//rd_test();
int t;
read(t);
while (t--) {
memset(f, 0, sizeof(f));
memset(match, 0, sizeof match);
int tot= 0;
int n, k;
cin >> n >> k;
for (int i= 1; i <= n; i++)
scanf("%s", s[i]);
int len= strlen(s[1]);
for (int i= 0; i < len; i++) { //对于每一位
for (char ch= 'a'; ch <= 'z'; ch++) {
for (int k= 1; k <= n; k++) { //对于每个字符串
//第k个字符串的第i个位置
if (s[k][i] == '?' || s[k][i] == ch) {
match[i][ch - 'a']|= (1 << (k - 1));
//第i位取ch的状态
}
}
}
}
int cnt= (1 << n) - 1;
f[0][cnt]= 1; //初始状态
for (int i= 0; i < len; i++) {
for (int j= 0; j <= cnt; j++) {
if (f[i][j]) { //如果f第i个位置的j状态有方案
for (char ch= 'a'; ch <= 'z'; ch++) {
//得到新状态
int now= (match[i][ch - 'a'] & j);
f[i + 1][now]= (f[i + 1][now] + f[i][j]) % mod;
}
}
}
}
for (int i= 0; i <= cnt; i++) { //枚举取字符串的所有状态
int ans= 0;
for (int j= 1; j <= cnt; j<<=1)
ans+= (bool)(i&j);
if (ans == k) //如果取了k个字符串(i中有k个1)
tot= (tot + f[len][i]) % mod;
}
printf("%d\\n", tot);
}
//Time_test();
}
以上是关于P2167 [SDOI2009]Bill的挑战的主要内容,如果未能解决你的问题,请参考以下文章
[BZOJ 1879][SDOI 2009]Bill的挑战 题解(状压DP)
BZOJ1879SDOI2009Bill的挑战 [状压DP]
[bzoj1879][Sdoi2009]Bill的挑战_动态规划_状压dp
bzoj 1879 [Sdoi2009]Bill的挑战(状压DP)