Loading

最短母串—题解

题面

怎么又是\(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 ;
}
posted @ 2021-07-01 18:59  Soresen  阅读(106)  评论(0)    收藏  举报