[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\n", ans); } }