ワード交流オートマトンオフ牛

トピックへのリンク:https://ac.nowcoder.com/acm/problem/20443

考える:この質問は、各単語の総数は、すべての単語に表示されて尋ねる今、言葉の多くを提供します。最初のステップは、辞書ツリーを構築して、ポインタを構築するために失敗し、再び最終的には全粒辞書ツリーノードトラバーサルすることです。

  トライの各ノードは異なる文字列(のみ、このノードへのルートからのパス)を表すので、我々ので回数は、我々は、最初に計算建設トライ時に各ノードを置くことができ回数の後にトライの各ノードは、計算され始め、そのノードによって表される文字列のすべての入力ワードのためのプレフィックス番号。

  例えば、我々は、単語aaは、AAB、ABAは、uがAAである特定のノードへのルートからトライからなる文字列は、次に我々が構築したトライが、数がので、これらのAAで、uが2である点を通過することが想定される有します表示されたプレフィックス番号などのワードが2(あるAAAAの B、ABA)。

  私たちは、その後、[u]が[U]はこのコンフィギュレーションが失敗するルートノードから事実を表し、フェイルポインタを構築する接頭辞との最後まで同じノードのuの長さ延長が同じである、我々は接頭辞文字列が発生してきたように数を数え、限り、我々の木他の文字列のサフィックスの数として計算全粒内の各プレフィックスとして、その後、表示された文字列の合計数は2倍の和です。そして、私たちが頼ることができる回数の合計は、私たちは、ポインタを構築するために失敗したときに、私たちは各プレフィックスを横断する最初でなければならない、線形へのポインタを得ることができないので、この接頭辞は確かにキューに最初に表示され、位置がキューにランクされます中に他の文字列 - >前に(これらの文字列をサフィックス、我々は接頭呼んでいるものがあります)。だから我々は、重ね合わせの方向における各点の統計情報の数は、ポインタを失敗キュー内のすべてのノードをトラバース逆にすることができます。最終的には、入力された単語に現れるすべてのトライプレフィックス番号を取得することができます。

コード:

#include <iostreamの> 
する#include <CStringの> 
する#include <アルゴリズム> 
の#include <キュー> 
の#include <地図> 
の#include <スタック> 
の#include <cmath> 
の#include <ベクトル> 
の#include < セット > 
の#include <cstdioを> 
書式#include < 文字列 > 
の#include <デック> 
 使用して 名前空間はstdを、
typedefの長い 長いLL。
#define EPSは1E-8
 の#define 0x3f3f3f3f INF
 の#define MAXN 2000005
 int型Q [MAXN];
 int型の TOT = 0、CNT = 0 、N-; 
 int型の失敗[MAXN]を、トライは[MAXN] [ 27 ]、NUM [MAXN]、posは[MAXN]; // NUMアレイレコード番号、POSアレイレコード辞書ツリー内の各単語ノード番号の末尾
文字S [MAXN];
 ボイド INSERT(INT LEN、INT インデックス){
     int型ルート= 0 ;
     のためのINT I = 0 ; IがLEN <; I ++は){
         int型 C = S [I] - [ A ' ;
         IF(トライ[ルート] [C] == 0 
        トライ[ルート] [C] = ++CNT; 
        ルート = トライ[ルート] [C]; 
        NUM [ルート] ++; // I(プレフィックス)が表示され、ノード終了番号num [i]のレコード列
    } 
    POS [インデックス]はルート=を; // レコード単語終了ノード番号で
}
 ボイド build_fail(){ // ビルドポインタ失敗
    のためにINT I = 0 ;私は< 26であり、Iは++ ){
         IF(トライが[ 0 ] [I])を{ 
            失敗[トライ[ 0 ] [ I] = 0 ; 
            Q [TOT ++] =トライ[ 0 ] [I]; 
        } 
    } 
    int型今= 0 ;
    一方、(今< TOT){
         int型、U = Q [今++ ]。
        以下のためにint型私= 0 ; iが< 26 ; iが++ ){
             場合(トライ[U]は[I]){ 
                失敗[トライ[U] [I] = トライ[I] [U]は[失敗します]。
                Q [TOT ++] = トライ[U] [I]。
            } { 
                トライ[U]は[I] = トライを[I] [U] [失敗]。
            } 
        } 
    } 
} 
int型のmain()
{ 
    scanf関数("%のD "およびN-);
     のためint型 I = 0、I <N - 、I ++ ){ 
        scanfの(" %のS " 、S);
         INT LEN = STRLEN(S); 
        INSERT(LEN、I); 
    } 
    build_fail( ); 
    のためのINT I = tot- 。1 ; I> = 0 ; i--)NUM [失敗[Q [I]]] + NUM = [Q [I]]; // 点の重ね合わせの方向に回数が失敗
    int型 I = 0のprintf(; I <N-I ++)は、 " %d個の\ N- "、NUM [POS [I]は]); // 以前に直接出力各ワードの終了位置、後に記録
    リターン 0 ; 
}

 

おすすめ

転載: www.cnblogs.com/6262369sss/p/11680775.html