【题目链接】
【题意】
给定 n 个字符串 S1~Sn,要求找到一个最短的字符串 T,使得这 n 个字符串都是 T 的子串。
【题解】
类似于搜索+二进制记录状态的题目
搜索时利用BFS来跑,每一个结点的位置都可以用状态数组存起来,
判断是否为 (1<<n)- 1 即可。
在输出答案时需要递归实现,所以要一个辅助数组fa来记录上一个结点的位置。

1 #include<queue>
2 #include<cstdio>
3 #include<cstring>
4 #include<algorithm>
5 using namespace std;
6 const int N = 6e3+5;
7 const int M = 2e6+50;
8 const int Str_N = 605;
9 int Trie[N][26],fail[N],End[N];
10 int vis[N][Str_N];
11 int Q[M],St[M];
12 int Fa[M];
13 char str[M];
14 int Head,Tail;
15 int n,idx;
16 char Str[Str_N];
17 void print(int x){
18 if(x==1) return ;
19 print(Fa[x]);
20 putchar(str[x]+'A');
21 }
22 void Insert( char s[] , int Id ){
23 int p = 0 ;
24 for(int i=0;s[i];i++){
25 int t = s[i]-'A';
26 if( !Trie[p][t] )
27 Trie[p][t] = ++idx;
28 p = Trie[p][t];
29 }
30 End[p] |= (1<<Id);
31 }
32 void Build(){
33 Head = 1 , Tail = 0;
34
35 for(int i=0;i<26;i++){
36 if( Trie[0][i] ){
37 Q[++Tail] = Trie[0][i];
38 fail[Trie[0][i]] = 0;
39 }
40 }
41
42 while( Head <= Tail ){
43 int u = Q[Head++];
44
45 for(int i=0;i<26;i++){
46 int To = Trie[u][i];
47 if( To ){
48 fail[To] = Trie[fail[u]][i];
49 Q[++Tail] = To ;
50 End[To] |= End[fail[To]];
51 }else{
52 Trie[u][i] = Trie[fail[u]][i];
53 }
54 }
55 }
56 }
57 void Solve(){
58 memset(Q,0,sizeof Q );
59
60
61 Head = 0 , Tail = 1;
62 Q[1] = St[1] = 0 ;
63 vis[0][0] = 1 ;
64
65 while( Head < Tail ){
66 int u = Q[++Head],S = St[Head];
67 for(int i=0;i<26;i++){
68 int To = Trie[u][i];
69 int Ts = S | End[To] ;
70 if( vis[Ts][To] ) continue;
71
72 Fa[++Tail] = Head ; Q[Tail] = To ;str[Tail] = i;
73 vis[Ts][To] = 1 ;St[Tail] = Ts ;
74
75 if( Ts == (1<<n)-1 ){
76 print(Tail);
77 putchar('\n');
78 return ;
79 }
80 }
81 }
82 }
83 int main()
84 {
85 scanf("%d",&n);
86 for(int i=0;i<n;i++){
87 scanf("%s",Str);
88 Insert(Str,i);
89 }
90 Build();
91 Solve();
92 return 0;
93 }
94
95 /*
96 *
97 4
98 HNOI
99 NOIP
100 NOI
101 IOI
102
103 HNOIPIOI
104 */
