最短母串—题解
怎么又是\(HNOI\)...
首先\(N\)很小,可以状压,压完之后看到一堆串,建一个自动机。
然后对所有的末尾节点打一个标记。
之后我们发现如果一个节点的\(fail\)有的标记,这个节点也应该有(必定包含后缀)。
这也是\(AC\)自动机中很经典的从\(fail\)继承信息。
然后我们只需要在自动机上\(bfs\),当状态满了的时候,输出方案就行了。
也是输出方案的题中比较经典的记录前趋了。
\(alls\)记录一共有多少个状态,\(ciner\)记录当前遍历到的状态。
还是那句话,一般最短的问题如果要搜索的话直接考虑\(bfs\)和\(id-Dfs\),能\(bfs\)还是最好\(bfs\)。
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <queue>
#include <iostream>
#include <bitset>
#define R register int
#define int long
#define printf Ruusupuu = printf
int Ruusupuu ;
using namespace std ;
typedef long long L ;
typedef long double D ;
typedef unsigned long long G ;
const int T = 6e2 + 10 ;
const int M = 5e1 + 10 ;
const int N = 1 << 13 ;
const int H = 27 ;
inline int read(){
int w = 0 ; bool fg = 0 ; char ch = getchar() ;
while( ch < '0' || ch > '9' ) fg |= ( ch == '-' ) , ch = getchar() ;
while( ch >= '0' && ch <= '9' ) w = ( w << 1 ) + ( w << 3 ) + ( ch ^ 48 ) , ch = getchar() ;
return fg ? -w : w ;
}
int n , cnt , st [T] , tr [T][H] , fail [T] , fa [T * N] , re [T * N] ;
char s [M] ; bool fg [T][N] ;
inline void ins( char s [] , int ix ){
int len = strlen( s + 1 ) , x = 0 ;
for( R i = 1 ; i <= len ; i ++ ){
int ch = s [i] - 'A' ;
if( !tr [x][ch] ) tr [x][ch] = ++ cnt ;
x = tr [x][ch] ;
} st [x] |= ( 1 << ( ix - 1 ) ) ;
}
void build(){
queue< int > q ;
for( R i = 0 ; i < 26 ; i ++ )
if( tr [0][i] ) q.push( tr [0][i] ) ;
while( !q.empty() ){
int x = q.front() ; q.pop() ;
for( R i = 0 ; i < 26 ; i ++ ){
if( tr [x][i] ) q.push( tr [x][i] ) , fail [tr [x][i]] = tr [fail [x]][i] , st [tr [x][i]] |= st [tr [fail [x]][i]] ;
else tr [x][i] = tr [fail [x]][i] ;
}
}
}
inline void debug( int x ){ cout << bitset< 10 > ( x ) << endl ; }
void bfs(){
queue< int > qaq , qwq ;
qaq.push( 0 ) , qwq.push( 0 ) ;
fg [0][0] = 1 ;
int ciner = 0 , alls = 0 ;
while( !qaq.empty() ){
int OvO = qaq.front() , ovo = qwq.front() ;
qaq.pop() , qwq.pop() ;
if( ovo == ( ( 1 << n ) - 1 ) ){
int llen = 0 , ans [T] ;
memset( ans , 0 , sizeof( ans ) ) ;
while( ciner ){
ans [++ llen] = re [ciner] ;
ciner = fa [ciner] ;
} for( R i = llen ; i ; i -- ) putchar( ans [i] + 'A' ) ; puts( "" ) ;
exit( 0 ) ;
}
for( R i = 0 ; i < 26 ; i ++ ){
if( !fg [tr [OvO][i]][ovo | st [tr [OvO][i]]] ){
fg [tr [OvO][i]][ovo | st [tr [OvO][i]]] = 1 ;
fa [++ alls] = ciner ;
re [alls] = i ;
qaq.push( tr [OvO][i] ) ;
qwq.push( ovo | st [tr [OvO][i]] ) ;
}
}
ciner ++ ;
}
}
void sc(){
n = read() ;
for( R i = 1 ; i <= n ; i ++ )
scanf( "%s" , s + 1 ) , ins( s , i ) ;
}
void work(){
build() ;
bfs() ;
}
signed main(){
sc() ;
work() ;
return 0 ;
}
$The \ light \ has \ betrayed \ me$

浙公网安备 33010602011771号