質問の意味:
タイプライターは、与えられた文字列、最低限必要なタイプされた文字列は、現在の新たな付加Pの文字列を過ごした後、現在の文字列の末尾に連続したサブ文字列の現在の文字列のコピーにQをとり、あり支出。
ソリューション:
DPと考えるのは簡単
ように私は、それぞれのために、私の前に最小コストプレイ文字を[i]はDPと呼ば
A = DP [I-1] + P
jが最小であり、その結果のs B = DP [J] + Q [J + 1〜I]はSの連続するサブストリングの[1〜j]の値
実際には、カットバッククリックこの文字列は、フロント部分の背面がサブストリングの一部ではない参照し、そうでない場合、後方カット移動を配置する場合、元の文字列の前部には、文字列が概略背面部分です。
DP [I] =分(A、B)
私は=時間で、kは、このような最適なカット点jを発見した場合は、その後、議論するとき、I = K + 1、および最適なカットポイントまたは元J、jはこの背中を配置する必要がありますされますかノルウェー。
jはすでに元の文字列最短のカットポイントを作った、そして今あなたがパターン文字列の後ろに何かを追加する必要があるため、なぜ、元の文字列は長く、短くすることはできません。
データ構造があり、後方Jを移動する過程では、操作の最初のカットのパターン文字列があった場合、問題があることに注意してください、フロントサポートは、操作文字列のこのモードでは、それをカット?
サフィックスオートマトン。行サブストリング内の複数のノードを表すサフィックスオートマトン、最長の一つであり、残りは連続最長サブサフィックスであり、親ノードは、サフィックスの子ノードであり、その後、自動機に連続するためサブ、それをカットのトップを置くか、それが元のノードにとどまり、またはそれは親ノードに転送されます。
サフィックスオートマトンの複雑さOをインクリメントするように構成された(1)、O(1)の状態遷移の複雑
Oの合計時間複雑度(N)
書式#include <cstdioを> する#include <アルゴリズム> 書式#include <CStringの> 使用して 名前空間はstdを、 #define MAXN = 200005 。 #define種類= 26 。 構造体状態 { 状態 *次の[種類]、* リンク。 int型のlen; 状態() { リンク = 0 。 LEN = 0 ; memsetの(次に、0、はsizeof (NEXT))。 } }。 int型SZを。 状態ST [MAXN* 2 + 5 ]。 インライン状態 * newnode(INT LEN = 0 ) { memsetの(ST [SZ] .Next、0、はsizeof [SZ] .Next(ST))。 ST [SZ] .link = 0 。 ST [SZ] .LEN = LEN。 返す&ST [++ SZ ]。 } 状態 *ルート、* 最後。 ボイド延びる(INT W) { ステート *のP = 最後; 状態 * CUR = newnode(P-> LEN + 1 )。 一方、(P && P->次に[W] ==0 ) { P - >次に[W] = CUR。 P = P - > リンク; } もし(P) { 状態 * Q = P-> 次に[W]。 もし(P-> LEN + 1 == Q-> LEN) CUR >リンク= - ; Q 他 { 状態 *クローン= newnode(P-> LEN + 1 )。 memcpy(クローン - >次に、Q->次に、はsizeof(Q-> NEXT))。 クローン - >リンク= Q-> リンク; Q - >リンク=クローン; CUR - >リンク= クローン; 一方、(P && P->次に[W] == Q) { P - >次に= [W] クローン。 P = P - > リンク; } } } 他 cur->リンク= ルート。 最後 = CUR。 } の#defineっ長い長 チャーS [MAXN]。 【MAXN] DP LL。 INT メイン() { ながら(〜のscanf(" %sの"、S + 1 )) { SZ= 0 ; ルート = newnode()。 最後 = ルート。 LLのP、Q; scanf関数(" %のLLDの%のLLD "、&P&Q)。 INT、N = STRLEN(S + 1 )。 int型 J = 1 ; DP [ 1 ] = Pと、 伸びる(S [ 1 ] - [ A ' ); 状態 * CUR = root->次に[S [ 1 ] - [ A ' ]。 以下のための(int型私は=2 ; iが<= N; iが++ ) { DP [I] = DP [I- 1 ] + P。 一方、(1 ) { ながら(!CUR =ルート&& cur->リンク- > LEN> = ij- 1)CUR = cur-> リンク。 もし(cur->次に[S [I] - [ A ' ]!= NULL) { CUR = cur->次に[S [I] - ' ' ]。 破ります; } 他の (S [拡張 - ++ J] " A " ); } // coutの<< I <<」「<< J <<てendl; DP [I] =分(DP [I]、DP [J] + Q)。 } のprintf(" %LLDする\ n " 、DP [N])。 } }
PS:私は、サブセット、サブ、セクション、サブ文字列、列、間隔の違いを理解したことがありません、一般的に「非連続したサブ文字列/配列」、「連続ストリング/シーケンス」を呼び出すために使用されます