题解 P2322【[HNOI2006]最短母串问题】

$\text{Link}$

题意

给出 $n$ 个互不包含的字符串 $a_{1,2,...,n}$,要求你求出一个字符串 $S$,使得 $\forall i\in[1,n],a_i\in S$,求 $\min|S|$。

$|a_i|\le50,1\le n\le 12$.

思路

首先我们看到有 $n$ 个字符串,感觉 $\text{KMP}$ 不怎么好做,于是我们考虑 $\text{ACAM}$。

然后这个 $n\le 12$ 非常奇怪,于是考虑状压 $\text{dp}$。

我们给每个节点赋值 $state_i$,若在 $\text{Trie}$ 上 $i$ 串以 $j$ 节点结尾则 $state_j\gets state_j\text{ or }2^{i-1}$,在建出 $\text{Fail}$ 树后,将 $state$ 再 $\text{or}$ 上当前节点的所有后缀。

然后我们从根节点开始 $\text{BFS}$,当按照字典序遍历到一个节点时,将当前状态 $\text{or}$ 上节点的 $statu$,若取到全局则将路径上的字符输出即可。

时间复杂度 $O(2^n\sum|a_i|)$。

代码:

#include<bits/stdc++.h>
using namespace std;
#define ll long long
namespace IO{//by cyffff

}
const int N=600+10,C=(1<<12)+1,S=N*C;
#define Tr ACAM.ch
int n,ans[S],pre[S],state[N],all;
char str[N];
bool vis[N][C];
struct node{
    int pos,state;
    node(int x=0,int y=0){pos=x,state=y;};
};
queue<node>q;
struct AC_AutoMaton{
    int fail[N];
    int ch[N][26],cnt=0;
    inline void insert(char *s,int n,int x){
        int cur=0;
        for(int i=1;i<=n;i++){
            int x=s[i]-'A';
            if(!ch[cur][x]) ch[cur][x]=++cnt;
            cur=ch[cur][x];
        }
        state[cur]|=1<<x-1;
    }
    inline void getfail(){
        queue<int>q;
        for(int i=0;i<26;i++){
            if(ch[0][i]) q.push(ch[0][i]);
        }
        while(!q.empty()){
            int cur=q.front();
            q.pop();
            for(int i=0;i<26;i++){
                if(!ch[cur][i]){
                    ch[cur][i]=ch[fail[cur]][i];
                }else{
                    int v=fail[cur];
                    fail[ch[cur][i]]=ch[v][i];
                    state[ch[cur][i]]|=state[ch[v][i]];
                    q.push(ch[cur][i]);
                }
            }
        }
    }
}ACAM;
int main(){
    n=read();
    all=(1<<n)-1;
    for(int i=1;i<=n;i++){
        readstr(str);
        ACAM.insert(str,strlen(str+1),i);
    }
    ACAM.getfail();
    q.push({0,0});
    vis[0][0]=1;
    int cnt=0,now=0;
    while(!q.empty()){
        node cur=q.front();
        q.pop();
        if(cur.state==all){
            stack<char>st;
            while(now){
                st.push(ans[now]+'A');
                now=pre[now];
            }
            while(!st.empty()) putc(st.top()),st.pop();
            return flush(),0;
        }
        for(int i=0;i<26;i++){
            int x=Tr[cur.pos][i],sta=cur.state;
            if(!vis[x][sta|state[x]]){
                vis[x][sta|state[x]]=1;
                q.push({x,sta|state[x]});
                pre[++cnt]=now;
                ans[cnt]=i;
            }
        }
        now++;
    }
}
posted @ 2021-06-22 13:15  ffffyc  阅读(9)  评论(0)    收藏  举报  来源