状态方程d[u][len][st],代表最后一个节点是u,长度为len,已经有st个串所能构成的密码数,记忆化搜索就行了。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
typedef long long LL;
using namespace std;
const int maxn=200+5;
int n,m;
struct Jason{
int ch[maxn][26];
int val[maxn];
int f[maxn];
int vis[maxn][40][1<<11];
LL d[maxn][40][1<<11];
char tmp[40];
int sz;
void clear() {
sz=1;memset(ch[0],0,sizeof(ch[0]));memset(vis,0,sizeof(vis));
memset(tmp,0,sizeof(tmp));memset(f,0,sizeof(f));memset(val,0,sizeof(val));
}
int idx(char ch) {return ch-'a';}
void insert(char *s,int v)
{
int u=0;
for(int i=0;s[i];i++)
{
int c=idx(s[i]);
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;
f[0]=0;
for(int i=0;i<26;i++)
{
int u=ch[0][i];
if(u) {f[u]=0;q.push(u);}
}
while(!q.empty())
{
int r=q.front();q.pop();
for(int c=0;c<26;c++)
{
int u=ch[r][c];
if(!u) {ch[r][c]=ch[f[r]][c];continue;}
q.push(u);int v=f[r];
while(v&&!ch[v][c]) v=f[v];
f[u]=ch[v][c];
val[u]|=val[f[u]];
}
}
}
LL dp(int u,int len,int st)
{
if(vis[u][len][st]) return d[u][len][st];
vis[u][len][st]=1;
LL &ans=d[u][len][st];
if(len==n)
{
if(st==(1<<m)-1) return ans=1;
else return ans=0;
}
ans=0;
for(int i=0;i<26;i++)
ans+=dp(ch[u][i],len+1,st|val[ch[u][i]]);
return ans;
}
void print_path(int u,int len,int st)
{
if(len==n){
for(int i=1;i<=n;i++) printf("%c",tmp[i]);printf("\n");
return ;
}
for(int i=0;i<26;i++){
tmp[len+1]='a'+i;
if(d[ch[u][i]][len+1][st|val[ch[u][i]]]) print_path(ch[u][i],len+1,st|val[ch[u][i]]);
}
}
};
Jason ac;
char s[40];
int main()
{
int kase=0;
while(scanf("%d%d",&n,&m)!=EOF)
{
if(n+m==0) break;
ac.clear();
for(int i=0;i<m;i++) {scanf("%s",s);ac.insert(s,1<<i);}
ac.getfail();
LL ans=ac.dp(0,0,0);
printf("Case %d: %lld suspects\n",++kase,ans);
if(ans<=42) ac.print_path(0,0,0);
}
return 0;
}