BZOJ 1195: [HNOI2006]最短母串 AC自动机+状压+搜索
思路比较直接.
由于 $n$ 很小,直接定义 $f[i][j]$ 表示当前在自动机中的节点 $i,$ 被覆盖串的集合为 $j$ 的方案数.
#include <bits/stdc++.h> #define N 750 #define M 150000 #define setIO(s) freopen(s".in","r",stdin) , freopen(s".out","w",stdout) using namespace std; int n,tot,edges,kk; int Log[30],hd[N],to[N],nex[N],mark[N][5000],fa[M*10],C[M*10]; char str[N]; queue<int>q; struct Sta { int u,sta,id; Sta(int u=0,int sta=0,int id=0):u(u),sta(sta),id(id){} }; queue<Sta>Q; struct Node { int sta,f,tag,ch[27]; }t[N]; void add(int u,int v) { nex[++edges]=hd[u],hd[u]=edges,to[edges]=v; } void insert(int xx) { int p=0,i,j,len=strlen(str+1); for(i=1;i<=len;++i) { int c=str[i]-'A'; if(!t[p].ch[c]) t[p].ch[c]=++tot; p=t[p].ch[c]; } t[p].tag=1; t[p].sta|=Log[xx]; } void build() { int i,j; for(i=0;i<27;++i) if(t[0].ch[i]) q.push(t[0].ch[i]),add(0,t[0].ch[i]); for(;!q.empty();) { int u=q.front();q.pop(); for(i=0;i<27;++i) { int qq=t[u].ch[i]; if(!qq) { t[u].ch[i]=t[t[u].f].ch[i]; continue; } t[qq].f=t[t[u].f].ch[i]; add(t[qq].f,qq); q.push(qq); } } } // 继承自己. void dfs(int x) { for(int i=hd[x];i;i=nex[i]) { int v=to[i]; t[v].sta|=t[x].sta; dfs(v); } } void print(int c) { if(C[c]==-1) return; print(fa[c]); printf("%c",C[c]+'A'); } int main() { int i,j; scanf("%d",&n); for(i=1;i<=14;++i) Log[i]=(1<<(i-1)); for(i=1;i<=n;++i) scanf("%s",str+1),insert(i); build(),dfs(0),C[0]=-1; for(Q.push(Sta(0,0,kk)),mark[0][0]=1;!Q.empty();) { Sta e=Q.front(); Q.pop(); if(e.sta==Log[n+1]-1) { print(e.id); return 0; } int v; int u=e.u; int idx=e.id; int sta=e.sta; for(i=0;i<27;++i) { v=t[u].ch[i]; if(!v) continue; if(mark[v][sta|t[v].sta]) { continue; } ++kk; fa[kk]=idx; C[kk]=i; mark[v][sta|t[v].sta]=1; Q.push(Sta(v,(sta|t[v].sta),kk)); } } return 0; }