[2019 가축 오프 더 학교 네번째] [G. 트리]

주제 링크 : 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 ; 
}
코드보기

 

추천

출처www.cnblogs.com/DeaphetS/p/11260559.html