주제 링크 : https://www.luogu.org/problem/P3796
질문의 의미 : 문자열 여러 모드와 텍스트 문자열, 문자열 일치는 가장 높은 숫자가 수, 이러한 문자열의 출력 패턴의 수를 필요로한다.
분석 : 분명히 일치의 수를 찾습니다 AC_qurey 기능은 거의 변화처럼 보이지만,이 모드 문자열의 출력 난 단지 트리는 아래에에 노드에 그것의 접속점에 복귀 할 수없는 그 시간에 분실 하고자하지, 사실이 아 같은 위치 기록의 배열과 다른, 매우 간단하고 분명하다. . . . 결국 사전 트리 노드 만 단어의 표시, 라벨 및 주문이 끝나기 전에 한 단어 변경됩니다.
우리는 초기화를 다시 할 때 청소 기능은 측면을 사용하는 방법을 많이 알고하지 않기 때문에 AC의 자동 장치가 초기화해야한다, 그래서 CNT가 증가 할 때마다 (즉, 새로운 에지가있다)
#INCLUDE <비트 / stdc ++ H.> 사용 스페이스 성병; CONST의 INT maxn 1E6 + = 10 ; CONST INT INF = 0x3f3f3f3f ; 타입 정의 긴 긴 LL; #DEFINE meminf (a) memset 함수 (a, 0x3F입니다,는 sizeof (a)) #DEFINE mem0 (a) memset 함수 (a, 0는 sizeof (a)); 구조체 결과 { INT의 NUM, POS; ANS} [ 200 ]; 부울 CMP ( CONST 결과 & A CONST 결과 및 b) { 경우 (a.num == b.num) 복귀 a.pos < b.pos; 반환 a.num> ; b.num } 구조체 노드 { int로 페일 단계; // 불일치 포인터 페일 INT VIS [ 26이다 ]; // 자식 노드의 위치, 즉 26 개 문자 트라이 것을 INT의 끝; // 만약 테일 노드가 기록되어있다 }를 AC [MAXN] CHAR S [ 200이다 [] 100 ] // 입력 패턴 문자열 CHAR SS [MAXN]; // 텍스트 문자열을 입력하는 데 사용 INT CNT = 0 ; // 트리는 포인터 무효화 클린 ( INT X) { ; MEM0 (교류 [X] .vis) 교류 [X] .END = 0; 교류 [X] .fail = 0 ; } 공극 INSERT ( 숯 * S, INT의 POS) { INT LEN = strlen 함수는 (S) int로 지금 = 0 ; // 트라이 현재 포인터 용 ( int로 된 I = 0 ; I은 <렌, 나는 ++ ) { // 트리는 트리 자식 노드 경우 (교류가 [지금]은 .vis는 [S가 [내가] - ' A는 ' ] == 0 )에 AC가 [지금]은 .vis 없음 [S [I] - ' ' ] ++ = CNT 클린 (CNT) // 입력 세트의 복수 번 필요 투명 투명, 노드 CNT ++ 이것을 사용할 필요가 이전 = 교류 이제 [현재]가 .vis [S [I] - ' ' ] } 교류 [현재] .END = POS; // 마크 노드가 제 1 플래그 인 단어의 끝, 그리고 몇 단어이다 } 보이드 get_fail () { 큐 < INT > 케; 위해 ( int로 I = 0 ; I는 < 26이고 , I는 ++) { // 0으로 설정되고 제 2 층의 포인터 실패 IF (교류가 [ 0 ] [I]를 .vis! = 0 ) { 교류 [교류가 [ 0 .] .vis [I]를] 페일 = 0 ; que.push합니다 (AC는 [ 0 ] [I]) .vis; } } 그동안 (! Que.empty ()) { INT U = que.front (); que.pop () 대 ( INT I = 0 ; I는 < 26이고 , I는 ++ ) { IF (교류는 [U]를 .vis [ I]! = 0 ) { // 현재 노드의 자식 노드가 존재하는 경우, 포인터가 노드는 현재 노드 포인터 실패에 대응하는 아이 노드 자식 노드 실패 AC는 [AC는 [U]는 [.vis I을 .] 실패 = 교류 [교류 [U] .fail] .vis [I]가, que.push합니다 (AC는 [U]를 .vis [I]가) } (가) 다른 교류는 [U]를 .vis [I] = 교류를 [교류 [U] .fail] .vis [I]; // 다른 직접에 자식 노드가 실패 현재 노드의 노드에 자식 노드 포인터에 해당하는 지점에 존재하지 않는 } } } 공극 AC_query ( 숯 *의 S) { INT LEN = strlen 함수 (S); int로 지금 = 0 ; 위한 ( int로 I = 0 ; I <렌, 난이 ++ ) { 이제 AC가 = [현재] [S가 [I] - .vis ' ' ]; 위한 ( INT의 t = 현재;! T = 0 t =가, {AC [t] .fail) ANS를 [AC [t] .END] .num ++를 ; } } } INT 의 main () { INT의 N; 동안 (~는 scanf ( "D의 % " , & )) N- { IF N (- == 0 ) BREAK , CNT = 0 ; 클린 ( 0 ); // 마다 새로운 가장자리, 이전 데이터 삭제 기억 에 대한을 ( INT I = . 1 ; I <= N-; I는 ++ ) { ANS [I] .num = 0 ; ANS [I] .POS = I] 는 scanf ( " %의 S " , S [I]); INSERT (S [I], I); } 교류 [ 0 ] .fail = 0 ; 종료 플래그 // } get_fail (); // 求出失配指针 는 scanf ( " % s의 " , SS); AC_query (SS); 정렬 (ANS + 1 , ANS + 1 + N, CMP); 의 printf ( " % D \ 없음 " , ANS [ 1 ]을 .num); 위한 ( int로 I = 1 ; i가 = N <; 내가 ++ ) { 경우 (ANS [I] .num == ANS [ 1 ] .num) { 의 printf ( " % S \ 없음 」,이야 [ANS [I]는 .POS ]); } 다른 휴식 ; } 반환 0 ; }