주제 링크 : https://ac.nowcoder.com/acm/contest/884/G
타이틀 효과 : 나무 \ (A \)을 감안할 때, 그럼 \ (T \) 심문 시간을주고, \ (A \)가 연결되어 얼마나 많은 서브 그래프 트리 \ (B_i \) 동형 물었다. \ (| A | \ LEQ 2000, t \ LEQ 10000 | B_i | \ 당량 (12) \)
해결 방법 :이 문제는 실제로이 질문에 762F의 버전 및 설명을 강화 Codeforces되고 , 여기에 도장하십시오
이 질문은이 질문을하기 전에 접근 방식과 비슷하지만 요청하는 많은 만 열 번까지 있기 때문에 또한 나무의 전처리 트리 DP 최소 표현 후,하지만, 그래서 더 이상 \ 이상 (12 \)의 모든 지점의 사전 열거을 고려 나무와 그들의 최소한의 표현을 찾을 수 있습니다. 나무의 전처리에 대한 모든 조건을 만족하는 방법, 내 방법은 포인트로서 현재 트리 \의 크기 (\ N-), 제 \ (N + 1 \)가 있다고 가정 현재 시점 또는 그 상위 아들 트리를 첨가하고, 나무가 크기 \ (12 \)에 도달 재귀 때까지 계속됩니다. 이러한 전처리 후 포인트의 수는 \ (8000 \) 개월 \ (12 \) 트리 적은을 초과하지 않는 것을 발견 할 것이다. 다음 단계 f를 설정 DP 대 트리 \ (A \)이다 [I]는 [j]가 \까지의 숫자 (I는 \) 수 \와 서브 트리의 루트 노드 (J \) 동형 트리를 나타내고, 다음 \ (ANS [J] = \하게 sum_ {I = 1} ^ {N} F [I] [J] \), 각각의 챌린지에 대한 응답이 \이기 (\ 합 ANS [J] \) 어디 \ 다른 지점에 대응 (J \) 트리 \ 때 루트 번호 (B의 \).
또한, 전처리시, 우리는 새로운 나무의 수와 트리의 루트에있는 숫자 \ (J의 \)를 숫자 \는 (내가 \) 트리 병합의 루트의 아들, 같은 사전 밖으로도 할 수 후에 때 합한 관계 미만 \ (14,000 \) 기이다. 열거 모든 이러한 결합 관계 계산 DP 트리 \ (A \)에 의해 수행 될 수있는 최적화 \이 부분의 시간 복잡도 (O (14000n) \)
#INCLUDE <비트 / stdc ++ H.> 사용 스페이스 성병; #DEFINE N 2,001 #DEFINE의 M 1 << 12 #DEFINE MM 8001 #DEFINE NN 16,773,121 #DEFINE MOD 1,000,000,007 INT LEN ( INT X) { 반환 32 - __builtin_clz (X)} int 형 유니온 ( INT (X), INT의 Y) { 창 (X << LEN (Y)) | Y} INT의 CNT; 설정 < INT > ID [ 13 ]; INT의 유니 [MM] [MM]; INT의 num_to_id [NN]; INTid_to_num [MM]; INT F [N] [MM]; 벡터 < INT > ID [ 13 ]; 구조체 트리 { INT SZ [N]; INT의 N, ANS [NN]; 벡터 < INT > D [N]; 벡터 < INT > MP [MM]; 보이드 리드 () { 는 scanf ( " %의 D ' , N); 위한 ( int로 I = 1 ; i가 ++; 나는 <= N ) [I]하는 명확한 ()을 (D); 위한 ( int로 난을 =2 ] 난 <= N; 내가 ++ ) { int로 U를 V; scanf와 ( " % d 개 %의 D ' , U, V); D [U] .push_back (V); D [V] .push_back (U); } } INT DFS ( INT CUR, INT 사전) { SZ [CUR] = 1 ; INT 입술 = 1 ; 벡터 < INT > TMP; 대 (자동 NXT : d [CUR]) 경우 (! = NXT 전) SZ tmp.push_back (DFS (NXT, 현재)), CUR]= + SZ [NXT]; 종류 (tmp.begin (), tmp.end ()); 대한 (자동 X : TMP) 고해상도 = 연합 (고해상도, 배); 입술 << = 1 ; 만약 CNT ++, MP [CNT] = TMP, id_to_num [CNT] = 입술, num_to_id [입술] = (num_to_id [입술]!) CNT; 위한 ( int로 I = 0 ; I ++은, 난 tmp.size () " ) { INT의 R = 1 ; 대 ( INT의 J = 0 ; J <tmp.size (); J ++) 경우 (! J = I) R = 조합 (R, TMP [J]); R << = 1 ; 유니 [num_to_id [R] [num_to_id [TMP [I]] = num_to_id [입술]; } ID [SZ는 [] CUR] 삽입 (num_to_id [입술).; 반환 입술을; } 공극 getID () 현재의 소재지 { 위해 ( int로 I = 1 난 ++; i가 N = < ) DFS을 (I, 0 ); } 공극 DP2 ( INT의 CUR, INT 사전) { SZ [CUR]은 = 1 ; F [CUR] [ 1 ] = 1 ; 대 (자동 NXT : d [CUR]) 경우 ! (= NXT전) { DP2 (NXT, 현재); 위한 ( int로 I = 분 ( 12 , SZ [CUR]); I> = 1 , 난 - ) 대 (자동 II : ID [I]) { INT의 V = F [CUR] [II]; 경우 (V!) 계속 ; 대 ( INT의 J = 1 ; J <= 분 ( 12 -i, SZ [NXT]); J ++ ) 대 (자동 JJ : ID [J]) (F [CUR] UNI [Ⅱ] [JJ] + = V * F [NXT] [JJ] %의 MOD) % = MOD; } SZ [CUR] + =SZ [NXT]; } 에 대해 ( int로 I = 1 ; 나는 = 분 (< 12 , SZ [CUR를]); 나는 ++ ) 을 위해 (자동 II : ID [I]) (ANS [Ⅱ] + = F [CUR] [II]) (%) = 모드; } } S, T; 설정 < INT > S; INT FA [ 13 ]; 벡터 < INT > D [ 13 ]; 보이드 대체 ( INT CUR, INT 사전) { FA [CUR] = 프리; 대 ( INT I = 1; 나는 = < 12 ; ++ i가 ) TD [I] = D의 [I]; TN = CUR; 경우 (현재의 == 12 ) {T.dfs ( 1 , 0 ); 반환 } INT X = CUR; 반면 (X! = 0 ) { D [X] .push_back (현재 + 1 ); 대체 (현재 + 1 , X); D [X] .pop_back (); X = FA [X]; } } INT 의 main () { 대체 ( 1, 0 ); 위한 ( int로 I = 1 ; i가 <= 12 ; I ++ ) 대 (자동 J : ID [I]) ID [I] .push_back (j); S.read (); S.DP2 ( 1 , 0 ); INT의 t; scanf와 ( " %의 D " , t); 반면 (t-- ) { T.read (); INT ANS = 0 ; s.clear (); 위한 ( int로 I = 1 ; I <= 테네시, 내가 ++ ) s.insert (T.dfs (I,0 )); 대 (자동 X : S) (ANS + = S.ans [num_to_id [X]) % = MOD; 의 printf ( " % D \ 없음 " , ANS); } 반환 0 ; }