フェイス質問
解決
最初のオファーPPT YYR
このPPTの基本的な考え方は明らかにされているが、他のいくつかの詳細があります
我々は$と$ Lの*(T + 1)$の後の$ Lの* tを特定し、暴力が明らかに前後にジャンプをジャンプすることはできません。$ LCP(のL * T、Lの*(T + 1))$の点まで戻ってジャンプジャンプを検討し、これは接尾辞配列+ RMQ高速なクエリを前処理を使用することができます。次に何それから、複数のサイクルフェスティバルがある場合は、その後、小さなトンが存在しなければならないので、同じ出発点に前方にジャンプします、1サイクル区間まで生産するために前方にジャンプし、前方にジャンプし、ループ部までの生成を検討ときにループ部を作るのだろうか?
= LENの%のL」セクション$ kを循環部分を越え順序$ LEN = LCP(のL * T、L×(T + 1))$ / L + 1 $ lenのノット$ RESの=のサイクルのケース番号、 $、明らかに少なくとも$ K = Lの前方にジャンプ場合 - $点」kは、サイクルのセクションを生成することができ、すなわち$のLCP(のL * TK、のL * TK + 1)\場合を満たすgeqslant Lの$ 、$ RES ++ $
コード:
書式#include <cstdioを> する#include <iostreamの> の#include <アルゴリズム> 使用して 名前空間はstdを、 const int型 MAXN = 50004 ; INT T、N、ANS。 INT SA [MAXN]、RK [MAXN]、モミ[MAXN]、秒[MAXN]、C [MAXN]、特開平[MAXN]。 チャーS [MAXN]。 無効Build_SAを() { INT、M = 26 。 以下のために(int型 i = 1 ; iは= N <; ++ I) FIR [I] = sの[I] - ' ' + 1 。 以下のために(int型 i = 0 ; I <= M; ++ I) C [I] = 0 ; 以下のために(int型 i = 1 ; iは= N <; ++ I) C [i]はモミ] ++ ; 以下のために(int型 I = 1 ; I <= M; ++ I) C [I] + = C [I- 1 ]。 以下のために(int型 I = N; I; - I) SA [FIR [C [I]] - ] = I。 用(int型のk = 1 ; K <= N; kは<< = 1 ) { int型、T = 0 ; 用(int型 - K + I = N 1 ++; iが<= N I) 秒【 ++ T] = I。 以下のために(int型 i = 1 ; iが<= N; ++ I) であれば(SA [I]> k)は 秒【 ++ T] = SA [i]は- kは、 以下のために(int型 i = 0 ; I <= M; ++ I) C [I] = 0 ; 以下のために(int型 i = 1 ; iは= N <; ++ I) C [FIR [秒[I]]] ++ ; 以下のために(int型 I = 1 ; I <= M; ++ I) C [I] + = C [I- 1 ]。 以下のために(int型 I = N; I; - I) SA [FIR [秒[I]]] C - ] =秒[I]、秒[I] = 0 ; 以下のために(int型 i = 1 ; iは= N <; ++ I) スワップ(FIR [I]、秒[I])。 T = 0 。 FIR [SA [ 1 ] ++ = T。 用(int型 iは= 2 ; iが<= N ++ I)の 場合(SEC [SA [I] =秒[SA [1-が!1 ] ||秒[SA [I] + K] =秒! [SA [I- 1 ] + K]) FIR [SA [I] = ++ T。 他の モミ[SA [i]を] = T; もし(T> = N)、 ブレーク。 M = T。 } 以下のために(int型 i = 1 ; iは= N <; ++ I) FIR [I] =秒[I] = 0 ; } 無効Get_heiを() { INT H = 0 。 以下のために(int型 i = 1 ; iは= N <; ++ I) RK [SA [I] = I。 以下のために(int型 i = 1 ; iは= N <; ++ I) { INT T = SA [RK [1] - 1 ]。 一方、(S [T + H] == sは[IはH +])H ++ 。 特開平[RK [I] =のH; H = MAX(0、H - 1 )。 } } INTのためのLG [MAXN]、MN [ 20 ] [MAXN]。 無効)(RMQを { 以下のために(int型 i = 1 ; iは= N <; ++ I) MN [ 0 ] [I] = 開平[I]。 用(INT J = 1 ; J <= LG [N]; ++ j)の ための(int型 iは= 1 ; I +(1 << J) - 1 <= N; ++ I) MN [J] [I] =分(M N [J- 1 ] [i]は、私[J- 1 ] [I +(1 <<(J- 1 ))])。 } INTクエリ(int型のx、int型のY) { もし(X> Y)スワップ(X、Y) 戻り分(MN [LG [Y-X] [X + 1 ]、MN [LG [YX] [Y-(1つの << LG [YX])+ 1 ])。 } int型のmain() { LG [ 0 ] = - 1 。 以下のために(int型 I = 1 ; I <= 50000 ; ++ I) LG [I] = LG [I >> 1 ] + 1 。 scanf関数(" %のD "、&T)。 しばらく(T-- ) { scanf関数(" %のD "、&N) チャー C [ 5 ]。 以下のために(int型 i = 1 ; iは= N <; ++ I) { scanf関数(" %sの" 、C)。 S [i]は = Cを[ 0 ]。 } S [N + 1 ] = 0 ; Build_SA(); Get_hei(); RMQ(); ANS = 1 。 以下のために(int型 I = 1 ; I <= N; ++ I) のために(int型、J = 1、J + I <= N; J + = I) { int型 L =クエリ(RK [J]、RK [J + I])。 INT RES = L / I + 1、K = I - 1%I。 もし(JK &&クエリ(RK [JK]、RK [JK + I])> = I) 解像度 ++ ; 年 = MAX(年RES); J + =リットル/私は* 私を。 } printf(" %d個の\ n " 、ANS)。 } リターン 0 ; }