AC 로스 자동 컴퓨터 템플릿 밸리 P3796

주제 링크 : 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 ; 
}

 

추천

출처www.cnblogs.com/qingjiuling/p/11375228.html