题目链接:https://onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3517
生成文本,要求含或不含某些连续子串的题目一般是 (AC) 自动机 (+) (dp) 的套路
设 (dp[u][len][st]) 表示当前在状态图的节点 (u),当前生成的文本长度为 (len),含子串的状态为 (st) 时的方案数
注意: 因为一个单词节点可能是多个单词的结尾((last) 函数的含义),所以在计算失配函数 (fail) 指针时要同时更新当前节点的 (last) 和 (val) 值
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn = 405;
int n, m;
int ok;
char s[20];
int ch[maxn][30], f[maxn], val[maxn], last[maxn];
ll dp[maxn][27][1<<11];
int sz = 0, rt = 0;
void init(){
sz = 0;
ok = (1<<m)-1;
memset(ch, 0, sizeof(ch));
memset(val, 0, sizeof(val));
memset(f, 0, sizeof(f));
memset(last, 0, sizeof(last));
memset(dp, -1, sizeof(dp));
}
int idx(char c){
return c - 'a';
}
void insert(int num){
int p = rt, len = strlen(s);
for(int i = 0 ; i < len ; ++i){
int c = idx(s[i]);
if(!ch[p][c]) {
++sz;
val[sz] = 0;
ch[p][c] = sz;
}
p = ch[p][c];
}
val[p] |= (1<<num);
}
void getfail(){
queue<int> q;
f[0] = 0;
for(int i = 0 ; i < 26 ; ++i){
int u = ch[0][i];
if(u) {
f[u] = 0; q.push(u); last[u] = 0;
}
}
while(!q.empty()){
int r = q.front(); q.pop();
for(int i = 0 ; i < 26 ; ++i){
int u = ch[r][i];
if(!u) {
ch[r][i] = ch[f[r]][i];
continue;
}
q.push(u);
int v = f[r];
while(v && !ch[v][i]) v = f[v];
f[u] = ch[v][i];
last[u] = val[f[u]] ? f[u] : last[f[u]];
val[u] |= val[last[u]]; //***
}
}
}
ll dfs(int u, int len, int st){
if(dp[u][len][st] != -1) return dp[u][len][st];
if(len == n) return dp[u][len][st] = (st == ok);
dp[u][len][st] = 0;
for(int i = 0 ; i < 26 ; ++i){
dp[u][len][st] += dfs(ch[u][i], len+1, st|val[ch[u][i]]);
}
return dp[u][len][st];
}
char ss[110];
int l = 0;
void print(int u, int len, int st){
if(len == n){
printf("%s
", ss+1);
return;
}
for(int i = 0 ; i < 26 ; ++i){
if(dp[ch[u][i]][len+1][st|val[ch[u][i]]]){
ss[len+1] = i+'a';
print(ch[u][i], len+1, st|val[ch[u][i]]);
}
}
}
ll read(){ ll s = 0, f = 1; char ch = getchar(); while(ch < '0' || ch > '9'){ if(ch == '-') f = -1; ch = getchar(); } while(ch >= '0' && ch <= '9'){ s = s * 10 + ch - '0'; ch = getchar(); } return s * f; }
int main(){
// freopen("ans.out", "w", stdout);
int kase = 0;
while(scanf("%d%d", &n, &m) == 2 && n){
memset(ss, 0, sizeof(ss));
init();
for(int i = 0 ; i < m ; ++i){
scanf("%s", s);
insert(i);
}
getfail();
ll ans = dfs(0, 0, 0);
printf("Case %d: ", ++kase);
printf("%lld suspects
", ans);
if(ans <= 42){
print(0, 0, 0);
}
}
return 0;
}