您的位置:首页 > 其它

字符串专项:LA 4126

2013-07-04 23:28 344 查看
一道AC自动机+状压DP,将M个字符串建一个AC自动机,注意将字符串插入tire树时,注意可能会有多个字符公用一个尾结点,需要注意val值的更新。

状态方程不难得出dp[dep][u][st]=sum{dp[dep+1][ch[u][i]][st|val[ch[u][i]]]|0<i<sigma_size},至于字典序打印方案,只需dfs一遍即可。

#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
typedef long long LL;
const int sigma=26;
int n,m;
char s[12][12];
int ch[110][sigma],val[110],sz;
int f[110];
void init(){sz=1;val[0]=0;memset(ch[0],0,sizeof(ch[0]));memset(val,0,sizeof(val));}
int idx(char c){return c-'a';}
void insert(char* s,int v)
{
int u=0,n=strlen(s);
for(int i=0;i<n;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 c=0;c<sigma;c++)
{
int u=ch[0][c];
if(u) {f[u]=0;q.push(u);}
}
while(!q.empty())
{
int r=q.front();q.pop();
for(int c=0;c<sigma;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[110][30][1<<10];
int vis[110][30][1<<10];
char rec[25];
LL dfs(int u,int l,int st)
{
if(l==n)
{
if(st==((1<<m)-1)) return dp[u][l][st]=1;
else return dp[u][l][st]=0;
}
if(vis[u][l][st]) return dp[u][l][st];
vis[u][l][st]=1;
LL& ans=dp[u][l][st];
for(int i=0;i<sigma;i++)
{
ans+=dfs(ch[u][i],l+1,st|val[ch[u][i]]);
}
return ans;
}
void print(int u,int l,int st)
{
if(l==n)
{
rec[l]=0;printf("%s\n",rec);return;
}
for(int i=0;i<sigma;i++) if(dp[ch[u][i]][l+1][st|val[ch[u][i]]])
{
rec[l]='a'+i;
print(ch[u][i],l+1,st|val[ch[u][i]]);
}
}
int main()
{
int kase=1;
while(scanf("%d%d",&n,&m)!=EOF)
{
if(!n&&!m) break;
init();
for(int i=1;i<=m;i++)
{
scanf("%s",s[i]);
insert(s[i],(1<<(i-1)));
}
getfail();
memset(vis,0,sizeof(vis));
memset(dp,0,sizeof(dp));
LL ans=dfs(0,0,0);
printf("Case %d: %lld suspects\n",kase++,ans);
if(ans<=42)
{
print(0,0,0);
}
}
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: