[HDU2825]Wireless Password

题意:给定$m$个字符串,要求你求出长度为$n$,且至少包含$m$个字符串中的$K$串的字符串的方案数。

题解:这题的$m$很小,只有10,所以可以考虑状压DP,先对这$m$个串构建AC自动机,然后设$f[i][j][s]$表示长度为$i$,目前在自动机上的节点是$j$,与这$m$个字符串匹配的情况是$s$的方案数,然后依赖AC自动机转移。


#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <bitset>
using namespace std;
#define reg register
inline int read() {
    int res = 0;char ch=getchar();bool fu=0;
    while(!isdigit(ch))fu|=(ch=='-'),ch=getchar();
    while(isdigit(ch)) res=(res<<3)+(res<<1)+(ch^48),ch=getchar();
    return fu?-res:res;
}
#define mod 20090717
int n, m, K;
int bin[11];
int nxt[105][26], fail[105], danger[105], tot;

inline void ins(char *str, int id)
{
    int len = strlen(str + 1);
    int now = 0;
    for (reg int i = 1 ; i <= len ; i ++)
        now = nxt[now][str[i]-'a'] ? nxt[now][str[i]-'a'] : nxt[now][str[i]-'a'] = ++tot;
    danger[now] |= bin[id - 1];
}

inline void Build()
{
    queue <int> q;
    for (reg int i = 0 ; i < 26 ; i ++) if (nxt[0][i]) q.push(nxt[0][i]);
    while(!q.empty())
    {
        int x = q.front();q.pop();
        for (reg int i = 0 ; i < 26 ; i ++)
            if (nxt[x][i]) fail[nxt[x][i]] = nxt[fail[x]][i], q.push(nxt[x][i]);
            else nxt[x][i] = nxt[fail[x]][i];
        danger[x] |= danger[fail[x]];
    }
}

int f[26][105][1<<10];

int main()
{
    bin[0] = 1;
    for(reg int i=1;i<=10;i++) bin[i]=bin[i-1]<<1;
    while(1)
    {
        n = read(), m = read(), K = read();
        if (!n and !m and !K) return 0;
        memset(nxt, 0, sizeof nxt), memset(fail, 0, sizeof fail);
        memset(danger, 0, sizeof danger);
        tot = 0;
        char str[15];
        for (reg int i = 1 ; i <= m ; i ++)
        {
            scanf("%s", str + 1);
            ins(str, i);
        }
        Build();
        memset(f, 0, sizeof f);
        f[0][0][0] = 1;
        for (reg int i = 0 ; i < n ; i ++)
        {
            for (reg int j = 0 ; j <= tot ; j ++)
            {
                for (reg int s = 0 ; s < bin[m] ; s ++)
                {
                    if (!f[i][j][s]) continue;
                    for (reg int p = 0 ; p < 26 ; p ++)
                    {
                        int to = nxt[j][p], sit = s | danger[to];
                        f[i + 1][to][sit] = (f[i + 1][to][sit] + f[i][j][s]) % mod;
                    }
                }
            }
        }
        bitset <11> bit;
        int ans = 0;
        for (reg int s = 0 ; s < bin[m] ; s ++)
        {
            bit = s;
            if ((signed)bit.count() >= K) {
                for (reg int j = 0 ; j <= tot ; j ++)
                    (ans += f[n][j][s]) %= mod;
            }
        }
        printf("%d
", ans);
    }
}
原文地址:https://www.cnblogs.com/BriMon/p/9841522.html