シリコンSJ +中間カット点を有し、我々はT上の切削点Iを列挙し、それをt [i]は、必要な数のSI最後の文字がtに一致させることができるように、[I + 1]の先頭文字としてSJをどのくらいの時間を一致させることができます
次いで、AC付きシーケンスS Nは、ロボット、自動抗ビルドマシンとSUM []アレイレコードTで一度正および負のマッチングtのそれぞれを構築[i]は、最後の文字列マッチングの数とすることができるように
注意:和アレーを求めている場合は、暴力は明らかにトンを失敗ジャンプします、アカウントに統計的なジャンプを服用すると、文字列のサフィックスと一致しないので、我々が構築したときに、あなたが失敗したこと置くことができる過程で、今末尾に追加することができますポインタを失敗しますこれ暴力的なジャンプが失敗避け、終わります
#include <ビット/ STDC ++ H> 使用して 名前空間STDを、 #define N 200005 構造体トライ{ INT NXT [N] [ 26 ]、失敗[N]、エンド[N]。 int型の根、L。 int型newnode(){ memsetの(NXT [L]、 - 1、はsizeof NXT [L])。 端[L] = 0 ; リターン L ++ ; } ボイドのinit(){ L ++ 。 ルート = newnode()。 } ボイドインサート(CHAR BUF []){ int型 LEN = STRLEN(BUF + 1 )。 int型になりました= ルート。 以下のために(int型 i = 1 ; iは= LEN <; iは++ ){ 場合(NXT [今] [BUF [I] - ' ' ] == - 1 ) NXT [今] [BUF [I] - [ A ' ] = newnode()。 今 = NXT [今] [BUF [I] - ' ' ]。 } [今]終了 ++ 。 } ボイドビルド(){ キュー < 整数 > Q; 【ルート】フェイル = ルートと、 以下のために(int型 i = 0 ; iは< 26 ; iは++ ) 場合(NXT [ルート] [I] == - 1 ) NXT [ルート] [I] = 根。 他{ [NXT [ルート] [I]失敗 = ルートと、 q.push(NXT [ルート] [I])。 } ながら(q.size()){ int型 =今)(q.front。 q.pop(); 以下のための(int型 I = 0;私は< 26 ; iが++ ) 場合(NXT [今] [I] == - 1 ) NXT [今] [I] = NXT [I] [今] [失敗します]。 他{ [NXT [今] [I]失敗 = NXTを[I] [今] [失敗]。 エンド[NXT [今] [I] + = 終わり[NXT [今] [i]と[失敗]。 q.push(NXT [今] [I])。 } } } int型の和[N]。 INTクエリ(CHAR BUF []){ int型 LEN = STRLEN(BUF + 1 )。 int型になりました=ルート; 以下のために(int型 i = 1 ; iは= LEN <; iは++ ){ 今 = NXT [今] [BUF [I] - ' ' ]。 和[I] + = 終わり[今]。 } } }。チャーBUF [N]、T [N]。 トライT1、T2。int型のn; ボイドリザーブ(CHAR S []){ int型 I = 1、J =用のSTRLEN(S + 1 )。 一方(iは< j)を{ スワップ(S [i]は、S [J])。++ I、 - J。 } } int型 メイン(){ t1.init()。 t2.init(); scanf関数(" %sの%のD "、T + 1、&N) 以下のために(int型私= 1 ; iが<= N; iが++ ){ scanf関数(" %sの"、BUF + 1 )。 t1.insert(BUF)。 リザーブ(BUF)。 t2.insert(BUF)。 } t1.build()。 t2.build(); t1.query(T)。 リザーブ(T)。 t2.query(T)。 INT LEN = STRLEN(T + 1 )。 長い 長い ANS =0 ; 用(int型 I = 0 ; iがLEN <; Iは++ ) ANS + =(長い 長い)t1.sum [I] * t2.sum [len- I]。 coutの << ANS << ' \ nを' ; }