题意:
已知一个长为n的字符串包含m个字串,问有多少种串满足
把m个字串构造为AC自动机,然后在这AC自动机上面进行DP
dp[len][u][S] 表示字串串长度为len,当前处于u位置,拥有S集合中的字串的方法数
当前的策略为选择走第len位填一个字符c,然后顺着自动机走。
自动机的每个节点保存拥有的字符串集合
#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <string>
#include <map>
#include <cmath>
#include <queue>
#include <set>
using namespace std;
//#define WIN
#ifdef WIN
typedef __int64 LL;
#define iform "%I64d"
#define oform "%I64d\n"
#define oform1 "%I64d"
#else
typedef long long LL;
#define iform "%lld"
#define oform "%lld\n"
#define oform1 "%lld"
#endif
#define S64I(a) scanf(iform, &(a))
#define P64I(a) printf(oform, (a))
#define P64I1(a) printf(oform1, (a))
#define REP(i, n) for(int (i)=0; (i)<n; (i)++)
#define REP1(i, n) for(int (i)=1; (i)<=(n); (i)++)
#define FOR(i, s, t) for(int (i)=(s); (i)<=(t); (i)++)
const int INF = 0x3f3f3f3f;
const double eps = 1e-9;
const double PI = (4.0*atan(1.0));
const int MAX_NODE = 250 + 20;
const int SIGMA_SIZE = 26;
int ch[MAX_NODE][SIGMA_SIZE];
int Fail[MAX_NODE], last[MAX_NODE];
int val[MAX_NODE];
int sz;
void init() {
sz = 1;
memset(ch[0], 0, sizeof(ch[0]));
}
void insert(char * s, int v) {
int u = 0, n = strlen(s);
for(int i=0; i<n; i++) {
int c = s[i] - 'a';
if(!ch[u][c]) {
memset(ch[sz], 0, sizeof(ch[sz]));
val[sz] = 0;
ch[u][c] = sz++;
}
u = ch[u][c];
}
val[u] |= v;
}
void getFail() {
queue<int> Q;
Fail[0] = 0;
for(int c=0; c<SIGMA_SIZE; c++) {
int u = ch[0][c];
if(u) { Fail[u] = 0; Q.push(u); last[u] = 0; }
}
while(!Q.empty()) {
int r = Q.front(); Q.pop();
for(int i=0; i<SIGMA_SIZE; i++) {
int u = ch[r][i];
if(!u) {
ch[r][i] = ch[Fail[r]][i];
continue;
}
Q.push(u);
int v = Fail[r];
while(v && !ch[v][i]) v = Fail[v];
Fail[u] = ch[v][i];
last[u] = val[Fail[u]] ? Fail[u] : last[Fail[u]];
val[u] |= val[last[u]];
}
}
}
const int MAXS = (1<<10) + 10;
LL dp[26][MAX_NODE][MAXS];
int n, S_ALL;
vector<string> anss;
char ss[40];
LL dfs(int len, int cur, int S) {
if(len == n) {
return S == S_ALL;
}
LL & ans = dp[len][cur][S];
if(ans != -1) return ans;
ans = 0;
for(int i=0; i<SIGMA_SIZE; i++) {
int v = ch[cur][i];
ss[len] = i + 'a';
ans += dfs(len+1, v, S|val[v]);
}
return ans;
}
void getAns(int len, int cur, int S) {
if(len == n) {
if(S == S_ALL) {
ss[len] = '\0';
anss.push_back(string(ss));
}
return ;
}
for(int i=0; i<SIGMA_SIZE; i++) {
int v = ch[cur][i];
ss[len] = i + 'a';
if(dp[len+1][v][S|val[v]])
getAns(len+1, v, S|val[v]);
}
}
char str[40];
int main() {
int m;
int kase = 1;
while(scanf("%d%d", &n, &m) != EOF && n+m) {
init();
for(int i=0; i<m; i++) {
scanf("%s", str);
insert(str, 1<<i);
}
getFail();
memset(dp, -1, sizeof(dp));
S_ALL = (1<<m) - 1;
LL ans = dfs(0, 0, 0);
printf("Case %d: %lld suspects\n", kase++, ans);
if(ans <= 42) {
anss.clear();
getAns(0, 0, 0);
sort(anss.begin(), anss.end());
for(int i=0; i<anss.size(); i++) {
puts(anss[i].c_str());
}
}
}
return 0;
}