누가 조정에 조정, 나는 그의 어머니는 빨판 코드를 전송하지 않은 누군지 사랑한다.
암호:
#INCLUDE <cstdio> #INCLUDE <알고리즘> #INCLUDE <CString을> 사용법 #include <문자열> #INCLUDE <벡터> 사용법 #include <지도> #DEFINE N 100007 #DEFINE INF 0x3f3f3f3f #DEFINE ULL 부호 오래 오래 코드가 기록 된 // 명이 사망했다. 네임 스페이스를 사용하여 표준; INT K1, K2; ULL 년, W; 문자 S [N]; 네임 스페이스 IO { 무효 setIO (문자열들) { = S +에서 문자열 "에."; . "밖으로"= S + 밖으로 문자열; freopen을 (in.c_str (), "R"표준 입력); // freopen을 (out.c_str (), "w", 표준 출력); } }; 구조체 SAM { #DEFINE M N << 1 , 부담 int로; 구조체 에지 { , w을 int로; 에지 (= 0 INT, INT w = 0)로 (에), w} {(w) }; 벡터 <엣지> G [M]; INT 사전 [M], CH [M] [26], MX [M] str_sam [M] sam_str [M], 깊이 [M]; 보이드는 초기화 () {TOT 지난 = = 1; } 공간 확장 (INT의 c) { INT의 순이익은 = ++ 어린 아이는, p는 지난 =; MX [NP = MX [P] + 1 = 마지막 NP; 대 (p는 && CH [P] [C]! 미리 p = [P]) CH [P] [C] = NP; (! P) 이전 [순이익] = 1 인 경우; 그밖에 { INT Q = CH [P] [C] 경우 (MX [Q] == MX [P] +1) 미리 [NP = Q; 그밖에 { NQ = INT ++ 모든; MX [NQ = MX [P] +1; memcpy가 (CH [NQ, CH [Q]를 sizeof (CH [Q])); [Q]를 미리 = NQ] 미리 [NP]를 미리 사전 = [Q] = NQ; 대 (p는 && CH [P] [C] == Q; p = [P] 사전) CH [P]을 [C] = NQ; } } } 보이드 Build_LCP () { INT의 strlen N = (S + 1), I, J, p = 1; 대해 (ⅰ = 1; 나는 <= N; ++ I) { p = CH [P] [S [N-1 +] - 'A']; sam_str [P] = N-1 +; str_sam [N-I + 1] = P; } 대 (ⅰ = 2; I <= TOT; I ++) { 경우 (MX [I]> K1) 깊이 [I] = 0; 다른 깊이 [I] = MX [I]; } 위한은 (i = 2; 나는 <= TOT; I ++) G [중고 [I]와 push_back EDGE ((I, 깊이 [I] -depth [중고 [I])).; } 보이드 Build_LCS () { INT의 strlen N = (S + 1), I, J, p = 1; 대해 (ⅰ = 1; 나는 <= N; ++ I) { p = CH [P] [S [I] - 'A']; sam_str [I] = 1; str_sam [I] = P; } 대 (ⅰ = 2; I <= TOT; I ++) { 경우 (MX [I]> K2) 깊이 [I] = 0; 다른 깊이 [I] = MX [I]; } 위한은 (i = 2; 나는 <= TOT; I ++) G [중고 [I]와 push_back EDGE ((I, 깊이 [I] -depth [중고 [I])).; } #undef를 M } LCP, LCS; 에 대한 네임 스페이스 { 벡터 <INT> G [N << 1]; INT t, 역, 모든; INT IS1 [N], IS2 [N]; INT의 DFN [N], S [N], DEP [N], 크기 [N], 아들 [N], 상위 [N], F [N], 발 [N], COL [N], 재 [N] ; ULL의 크기 1 [N], SIZE2 [N] sizew [N]; ULL SUM1 [N], SUM2 [N] sumw [N]; 부울 CMP (INT의 B, A INT) { DFN 복귀 [A] <DFN [B] } 보이드 get_dfn (INT의 X, INT FA) { DFN [X] = t ++; 크기 [X] = 1; F [X] = 일; 대해 INT (I = 0; I는 <lcp.G [X] 크기는 (); I ++) { INT의 lcp.G Y = [X] [I] .TO; (Y == FA)가 계속되는 경우; get_dfn (Y, X); DEP [Y] = DEP [X] + 1; 크기 [X] + = 크기 [Y]; 경우 (크기 [Y] "의 크기 [아들 [X]) 아들 [X = Y; } } 보이드 DFS2 (INT U, INT TP) { 가기 [U] = TP; 경우 (SON [U]) DFS2 (SON [U] TP); 경우 (나는 <lcp.G [U] 크기는 (); INT 난 = 0 ++ I) { V = INT lcp.G [U] [I] .TO; 경우 (V == 아들 [U] || V == F [U]) 계속; DFS2 (V, V); } } INT LCA INT (X, Y의 INT) { 반면 (상부 [X]! = 가기 [Y]) { DEP [가기 [X]> 출발 [가기 [Y] X = F [가기 [X] : Y = F [가기 [Y]; } [X] <출발을 증착 복귀 [Y] X : Y;? } 보이드 _new (INT의 X, V INT, INT의 c) { 최대 ++; 다시 [모든] = X; 발 [X] = V; COL [X] = C; 경우 (c == 1) IS1 [X] = 1; 다른 IS2 [X] = 1; } 보이드 addvir (INT의 X, Y INT) { G [X] .push_back (Y); } 무효 초기화 () { t = 0; get_dfn (1,0); DFS2 (1,1); } 삽입 공간 (INT의 X) { 만약 STA (<= 1) { S는 [++이다] = X; 반환; } INT LCA LCA = (S [STA, X); 경우 (LCA == S [STA]) S [++ STA] = X; 그밖에 { 동안 STA (> 1 && DEP [S [STA-1]> = DEP [LCA]) addvir (S [STA-1], S [STA), - STA; 경우 (S [STA] == LCA) S [++ STA] = X; 그밖에 { addvir (LCA, S [STA]); S [STA] = LCA; S는 [++이다] = X; } } } 무효 빌드 () { 그것은 = 0이고; 정렬 (재 + 1 + 1 + 재 TOT, CMP); 경우 (재 [1] = 1!) S [++ STA] = 1; 위한 (INT 난 = 1; I <= TOT; I ++)를 삽입 (재 [I]); 동안 STA (> 1) addvir (S [STA-1], S [STA), - STA; } 보이드 DP (INT의 X) { 대해 INT (I = 0; I <G [X] 크기는 (); I ++) { INT Y = G [X] [I]; DP (Y); 크기 1 [X] + = 크기 1 [Y]; SIZE2 [X] + = SIZE2 [Y]; SUM1 [X] + = SUM1 [및]; SUM2 [X] + = SUM2 [Y]; } ULL TMP = 0; 울 cntw = 0; ULL CUR = 0; 대해 INT (I = 0; I <G [X] 크기는 (); I ++) { INT Y = G [X] [I]; TMP = + (SUM1 [X] -sum1 [Y]) * SIZE2 [Y]; TMP = + (SUM2 [X] -sum2 [Y]) * 크기 1 [Y]; cntw + = (크기 1 [X] -size1 [Y]) * SIZE2 [Y]; } CUR + = (TMP) * lcp.depth [X]; CUR - = (cntw) * W * lcp.depth [X]; CUR IS1 + = [X] * SIZE2 [X] * 브로 [X] * lcp.depth [X] + IS2 [X] * 크기 1 [X] * 브로 [X] * lcp.depth [X]; CUR - = (IS1 [X] * SIZE2 [X] * W + IS2 [X] * 크기 1 [X] * W); 년 + = 심장 / 2; 크기 1 [X] + = IS1 [X]; SIZE2 [X] + = IS2 [X]; SUM1 [X] + = IS1 [X] * 브로 [X]; SUM2 [X] + = IS2 [X] * 브로 [X]; } ) (해결 무효화 { 짓다(); DP (1); 위한 (INT 난 = 1; I <= TOT; I ++) { 다시 [I] = 브로 [I] = SUM1 [I] = SUM2 [I] = 크기 1 [I] = SIZE2 [I] = IS1 [I] = IS2 [I] = 0; G [I]하는 명확한 (); 다시 [I] = 0; } TOT = 0; 그것은 = 0이고; } }; // 가상 트리 모든 에지 값 int = 1; INT totsize, RT1, RT2, MX, ED, LSC, RSC; INT HD [N << 3] 힘 [N << 3], 크기 [N << 3]; 구조체 에지 { 에 INT, NEX w; } 즉 [N << 3]; 구조체 노드 { 그리고, DIS, 발; 노드 (나와는 0, = 0 DIS는, 넌 VAL = = 0) 및 (U), DIS (DIS), 발 (발)을 {} } L [N << 2], R [N << 2]; 보이드 add_div (INT의 X, Y INT, INT의 z) { E [++ 에지] .nex HD = [X] HD [X] = 가장자리 E [에지] .TO = Y, E [에지] .W = Z; } 보이드 Build_Tree (INT의 X, INT FA) { INT FF = 0; 대해 INT (I = 0; I는 <lcs.G [X] 크기는 (); I ++) { INT의 lcs.G Y = [X] [I] .TO; (Y == FA)가 계속되는 경우; 만약 (! FF) { FF = X; add_div (FF, Y lcs.G [X] [I] .W); add_div (Y, FF, lcs.G [X] [I] .W); } 그밖에 { 최대 ++; add_div (FF도, 0); add_div (모두, FF, 0); add_div (TOT, Y lcs.G [X] [I] .W); add_div (Y, TOT, lcs.G [X] [I] .W); FF = 최대; } Build_Tree (Y, X); } } 보이드 find_edge (INT의 X, INT FA) { 크기 [X] = 1; 대해 INT (I = HD는 [X] 나, 나는 전자 = [I] .nex) { INT Y = E [I] .TO; 경우 (Y == FA || 힘 [I]) 계속; find_edge (Y, X); 크기 [X] + = 크기 [Y]; 이제 최대 = INT (크기 [Y] totsize 크기 [Y]); 경우 (현재 <MX) { MX는 이제 =; ED = 1; RT1 = X, RT2 = Y; } } } (INT FA의 INT (X), INT DEP, INT 타이) 보이드 get_node { 경우 (TY == 0) { 경우 (lcs.sam_str [X]) L [++ LSC = 노드 (lcs.sam_str [X] lcs.mx [X] -dep, DEP); } 그밖에 { 경우 (lcs.sam_str [X]) R [++ RSC = 노드 (lcs.sam_str [X] lcs.mx [X] -dep, DEP); } 대해 INT (I = 0; I는 <lcs.G [X] 크기는 (); I ++) { INT의 lcs.G Y = [X] [I] .TO; 경우 (힘 [I] || Y == FA) 계속; get_node (Y, X, DEP + lcs.G [X] [I] .W, TY); } } 보이드 Divide_And_conquer (INT의 X) { (totsize == 1) 돌아 가면; MX = INF; RT1 = RT2 = ED = 0; find_edge (X, 0); 뷰 [ED] 정도 = [ED ^ 1] = 1; LSC = RSC = 0; get_node (rt1,0,0,1); get_node (rt2,0,0,2); 위한 (INT 난 = 1; I <= LSC; I ++) 비르 :: _ 새로운 (lcp.str_sam [L [i]를 .u], L [i]를 .dis, 1); 위한 (INT 난 = 1; I <= RSC; I ++) 비르 :: _ 새로운 (lcp.str_sam [R [i]를 .u], R [i]를 .dis, 2); W = E [ED] .W; 대한 :: 해결 (); INT tmprt1 = RT1, RT2 = tmprt2; INT sizert1 크기 = [RT1, sizert2 = totsize 크기 [RT1]; totsize = sizert1; Divide_And_conquer (tmprt1); totsize = sizert2; Divide_And_conquer (tmprt2); } () 주요 int로 { IO :: setIO ( "입력"); INT I, J, N; scanf와 ( "% S % D % D", S + 1, K1, K2); N = strlen 함수 (S + 1); lcp.Initialize (); lcs.Initialize (); 대해 (ⅰ = 1; 나는 <= N; ++ I) { lcs.extend (S [I] - 'A'); lcp.extend (S [I + N-1] - 'A'); } lcs.Build_LCS (); lcp.Build_LCP (); lcs.tot 모든 =; Build_Tree (1,0); 대한 :: 초기화 (); totsize = N; 의 printf ( "%의 LLU \ n", ANS); 0을 반환; }