洛谷题单指南-状态压缩动态规划-P2167 [SDOI2009] Bill的挑战

原题链接:https://www.luogu.com.cn/problem/P2167

题意解读:求与n个模版字符串中的k个能匹配的字符串个数,匹配要求字符串长度相等,且对应位置的字符相同或者模版中是‘?’。

解题思路:

解题的关键在于要一位一位的看目标字符串能取的字符,取到某个字符之后,能与哪些模版字符串匹配。

我们可以定义状态g[i][j]表示当目标字符串第i位取字符j(a~z)的时候,有哪些模版字符串能与之匹配,二进制位为1的表示能匹配的模版字符串。

接下来,进行dp相关的状态设计:

设f[i][j]表示已匹配到字符串前i位(注意与g定义的不同),当前能与目标串匹配的模版字符串状态为j时的目标字符串的个数

那么,在状态转移时,当前已匹配到第i位,当前目标串状态为j,

接下来要考虑第i+1位能取什么字符,枚举c:'a'~'z',此时f[i][j]能给贡献的状态必然是 g[i][c] & j,

因此有f[i +1][g[i][c] & j] += f[i][j]

初始化:f[0][(1 << n) - 1] = 1

结果:所有状态s中1的个数为k的f[strlen][s]之和,注意计算中取模。

另外,在状态转移时,如果f[i][j] = 0,则可以剪枝,不必枚举c,因为贡献加上去没意义。

100分代码:

#include <bits/stdc++.h>
using namespace std;

const int N = 15, M = 55, MOD = 1000003;
int g[M][26];
int f[M][1 << N];
string ss[N];
int t, n, m, k;

int count1(int x)
{
    int res = 0;
    while(x)
    {
        res++;
        x -= (x & -x);
    }
    return res;
}

int main()
{
    cin >> t;
    while(t--)
    {
        cin >> n >> k;
        memset(g, 0, sizeof(g));
        memset(f, 0, sizeof(f));
        for(int i = 0; i < n; i++) cin >> ss[i];
        m = ss[0].size(); //字符串的长度

        for(int i = 0; i < m; i++)
        {
            for(int j = 0; j < 26; j++)
            {
                for(int k = 0; k < n; k++)
                {
                    if(ss[k][i] == '?' || ss[k][i] - 'a' == j)
                    {
                        g[i][j] |= (1 << k);
                    }
                }
            }
        }

        f[0][(1 << n) - 1] = 1;
        for(int i = 0; i < m; i++)
        {
            for(int j = 0; j < 1 << n; j++)
            {
                if(!f[i][j]) continue;
                for(int c = 0; c < 26; c++)
                {
                    f[i + 1][g[i][c] & j] = (f[i + 1][g[i][c] & j] + f[i][j]) % MOD;
                }
            }
        }

        int ans = 0;
        for(int i = 0; i < 1 << n; i++)
        {
            if(count1(i) == k) 
            {
                ans = (ans + f[m][i]) % MOD;
            }
        }

        cout << ans << endl;
    }

    return 0;
}

 

posted @ 2025-09-03 16:04  hackerchef  阅读(7)  评论(0)    收藏  举报