루오 구 P3809 [템플릿] 접미사 정렬 접미사 배열

URL : https://www.luogu.org/problem/P3809

질문의 의미 :

문자열의 모든 접미사는 사전 식 순서로 정렬. 문자열 길이는 $의 1E6의 $ 미만입니다.

해결 방법 :

베어 접미사 배열, 원리는 제 시작 위치는 I는 $ I 번째 키워드와 + 1 $가 키워드 그때 그때 $ 새로운 제 키를 획득하기 위해 결합되며, $ 제 키로 $ 접미사이다 I는 제 2 명 키로을 $ + 승산하고,이어서 결합. 특정 구현 코드의 주석을 참조하십시오 :

참고 블로그 :

https://www.cnblogs.com/victorique/p/8480093.html

https://www.luogu.org/blog/black-jokers/solution1-p3809

https://www.cnblogs.com/ezoiLZH/p/9607849.html

AC 코드 :

#INCLUDE <비트 / STDC ++ H.> 
네임 스페이스를 사용하여 STD; 
CONST의 INT의 MAXN = 1,000,005; 
구조체 접미사 배열 
{ 
    INT N-, m, 
    int로 세 [MAXN, 랭크 [MAXN, TP [MAXN, SA [MAXN]; 
    // SA는 [I]가 = J, i 번째의 이름이 처음부터 J 접미사 (참고 입금 첨자) 
    // 순위 [I]는 = J 접미사 J의 시작부터 i는 이름은 (그리고 상호 SA , 위치 (값)) 
    // TP [I]의 두번째 인덱스를 저장 처음부터 키워드 첨자 I에 J (제 키워드 SA 어레이 상당) 인 
    세금 // [I] = J, 난 (기수 정렬은 값 터브)와 J를 갖는 키워드 제 번호 나타내고 
    ; 숯 CH [MAXN]는 
    공극 정렬 () // 기수 정렬 
    { 
        위해 (ⅰ = 0 나타내는 int i가 <를 = m; ++ I) //는 클리어 터브 
            [I]가 = 0 세제; 
        대해 INT (I = 1]. I는 <= N-; I는 ++)에 대응하는 배럴의 각각에 // 번호로부터 얻어진다 첫 번째 키는 랭크 [I] 이름의 개시 나 접미사이다 
        // 순위 접미사 세금들은 [랭크 [내가]]을  
            ++ 세금 [순위 [I]] ;
        위한은 (INT I = 1; I <= m; I ++) / / 플러스 버킷 앞에 정렬이 완료되면 순위를 얻을 수 있습니다
            세금 [I] + = 세금 [1- 난.] 
        에 대해 - 난 // 접미사 (; I> = 1 INT I = N-. ⅰ) 제 키워드 TP [I]의 첨자는, 세제 [랭크 [TP는 [내가]]] = J의 내가 두 번째 열쇠이다 
        접두사 때문에 기수 정렬 모색 한 후, 접미사 // 단어 첫 번째 키워드는 첫 번째 키워드 가진 J 접미사이며, 이미 순위는 그렇게 알고 풋 
        TP 대응 @ 접미사 순위 [I]를 기록하면서 감소 된 랭크된다. 때마다 나는 두 번째 키 접미사의 첫 번째 키 가지고 
        이 정렬, 두 번째 키에 해당하는 같은처럼 첫 번째 키워드에 따라, 마지막 키워드 내지 제 // 접미사 두 번째 장애물 경우, 
        // 키워드 후가 동일하지 않습니다, 첫 번째 큰 키워드가이 시간을 기준으로 더 확실한 보장하기 위해 그 제 1 및 제 2 키워드로 분류. 
            SA [세 [순위 [TP [I]를] - = tp를 [I]; 
    } 
    BOOL CMP (A INT, INT의 B, INT K) 
    { 
        //의 TP 이제 마지막 순위 인 
        전항 // 는 sa에서 의미하는 [I]와 SA의 시작 [I-1] 접미어의 시작 동일한 순위인지, 
        // 항목 마찬가지로 후 J의 첨가 비교 순위가 두 번째 키는 것을 의미 후에. 교차없이 보장 
        복귀 TP를 [A] == TP [B] && TP [A + K] == TP [B + K] 
    { 
        N- = 나 strlen. (CH의 + 1); 
    }
    get_sa 공극 () 
        (.; I <= N-; INT I = 1 ++ I)에 대한 
            m = 최대 (m, 랭크 [I] = CH [I] - '0'), TP [I] = 1; // ASCII 코드의 첫 번째 라운드 첫번째 키 누름, 제 눌러 번호 키 
        정렬 (); // 기수 정렬의 제 라운드 
        (INT를 p = 0, J = 1; p <N; J << = 1, P = m) 
        { 
            P = 0; // 클리어 
            용은 (= I 값 int 1;. 난 <= J가, 난 ++)는 
                TP [P ++] = N-J-I + // 후자 이하 접미사 I 바닥면에 따라서, 제 키의 길이를 줄임으로써, J, 단지 자체가 증가 
            대해 INT (I = 1]. I <= N-; I는 ++) 
                IF (SA [I]> J) 
                    TP [++의 P = SA [ I] -j // SA [I]> J 증명 픽스 길이 난 J, TP [SA [I]보다 큰 -j] 첨자 SA가 [I] -j 번째 키워드 반면, 아직 순서가 
            일종의 (); // 두 번째 라운드와 기수 정렬을 넘어 
            스왑 (순위, TP); // TP 아무 소용이, 우리가 TP에 복사 된 정보를 평가합니다. 동안 빈 랭크 
            랭크 [사행 [1] = p = 1; // 정렬에서 수행 새로운 SA 기록 빈 랭크의 대응 관계,
            경우 (; 나는 = <N; I ++ = 2 int로 I) 
                랭크 [SA [I]는 = CMP (SA [I], SA [-I 1., J) P ++? 피;
        } 
    } 
}; 
접미사 배열의 SA; 
INT의 main () 
{ 
    //scanf("%d",&sa.n); 
    scanf와 ( "%의 S"sa.ch + 1); 
    sa.get_sa (); 
    대해 INT (I = 1; I <= sa.n; I ++) 
        의 printf ( "% d 개 %의 C"sa.sa [I] (I sa.n == '\ n'? ') ); 
    0을 반환; 
}

  

추천

출처www.cnblogs.com/Aya-Uchida/p/11361472.html