[2019頭の牛オフより学校第四] [G.ツリー]

トピックへのリンク:https://ac.nowcoder.com/acm/contest/884/G

タイトル効果:ツリー\(\)を考えるが、その後、\(T \)尋問時間を与える、と\(A \)が接続されているどのように多くの部分グラフツリー\(B_i \)同型を尋ねました。\(| A | \当量2000、T \当量10000、| B_i | \当量12 \)

解決策:この問題は、実際に762Fの拡張バージョンをCodeforcesされており、この問題についての説明は、ここにスタンプしてください

   この質問は聞いて、そう\(12 \)を超えないのすべてのポイントの前の列挙を検討する前に、この質問のアプローチに似ていますが、また、ツリーの前処理ツリーDPの最小表現の後に、しかしとして多くの千10倍もあるので、木とは、その最小限の表現を見つけます。木の前処理のための全ての条件を満足する方法を、私の方法は、点として現在のツリー\のサイズ(\ N-)、最初の\(N + 1 \)のものとする現在のポイントまたはその祖先息子はツリーを追加し、そしてツリーは、サイズ\(12 \)に達するまで再帰的に続けています。このような前処理後のポイントの数は\(8000 \)ヶ月未満\(12 \)ツリーを超えていないでしょう。次のステップは、[I] [j]が\に数が(私は\)番号\(J \)同型ツリーとサブツリーのルート・ノードであることを示しセットF、DPのツリー\(\)であります次に\(ANS [J] = \作る sum_ {i = 1} ^ {n}はF [I] [J] \)、 各課題に対する答えが\されるため(\和ANS [J] \)、 ここでルートの数(Bの\)の異なる点に対応する\(J \)ツリー\。

   また、前処理の時点で、我々はまた、プリアウト時に番号の後に新しい木の数として、ツリーのルートに数\(j個\)することができます\(私は\)ツリーマージの根の息子である、など合わせた関係未満\(14,000 \)基です。列挙は、すべてのそのような組み合わせの関係が算出されるDPツリー\(\)により行うことができる、最適化\のこの部分の時間的複雑度(O(14000n)\)

#include <ビット/ STDC ++ H>
 使用して 名前空間STDを、
#define N 2001
 の#define M 1 << 12
 の#define MM 8001 
 の#define NN 16773121
 の#define MOD十億七
 INT LEN(INT X){ 返す 32 - __builtin_clz(x);}
 int型連合(int型のx、int型の Y){ リターン(X << LEN(Y))| Y;}
 int型のCNT。
設定 < 整数 > ID [ 13 ]。
int型のユニ[MM] [MM]。
int型のnum_to_id [NN]。
int型id_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型私= 1 ; iが<= N; iが++ 
        D [i]を.clear(); 
      以下のためのint型私は=2 ; iが<= N; iが++ 
        { 
        int型V、Uと、
        scanf関数(" %d個の%d個"、&​​U&V); 
        D [U] .push_back(V)。
        D [V] .push_back(U)。
        } 
      } 
    int型 DFS(INT CUR、INT PRE)
      { 
      SZ [CUR] = 1 int型 RES = 1 ; 
      ベクトル < int型 > TMP;
      以下のための(自動NXT:D [CUR])の場合(!NXT = 前)
        SZ tmp.push_back(DFS(NXT、CUR))、[CUR]+ = SZ [NXT]。
      ソート(tmp.begin()、tmp.end()); 
      以下のための(自動X:TMP)RES = 連合(RES、x)は、
      RES << = 1 もし CNT ++、MP [CNT] = tmpに、id_to_num [CNT] = resを、num_to_id [RES] =(num_to_id [RES]!)CNT;
      以下のためにint型 i = 0 ; iは++; iがtmp.size()< 
        { 
        int型の R = 1 以下のためのint型 J = 0 ; jの<tmp.size(); J ++)の場合(!J = I)
          R = 連合(R、TMP [J]); 
        R << = 1
        UNI [num_to_id [R] [num_to_id [TMP [I]]] = num_to_id [RES]。
        } 
      ID [SZ [CUR](num_to_id [RES])を挿入します。
      リターンのres; 
      } 
    ボイドのgetId()
      { 
      ためint型 i = 1 ; iが<= N; iが++ 
        DFS(I、0 ); 
      } 
    ボイド DP2(INT CUR、INT PRE)
      { 
      SZ [CUR] = 1 
      F [CUR] [ 1 ] = 1 以下のための:(D [CUR]オートNXT)の場合(NXT =!PRE)
        { 
        DP2(NXT、CUR)。
        以下のためにint型 I =分(12、SZ [CUR]); I> = 1 ; i-- のための(自動II:ID [I])
            { 
            int型 V = F [CUR] [II]。
            もし(!v)を続けますINT J = 1 ; J <=分(12 -i、SZ [NXT]); J ++ のための(自動JJ:ID [J])
                ([UNI [II] [JJ] [CUR] F + = V * F [NXT] [JJ]%MOD)%= MOD。
            } 
        SZ [CUR] + =[NXT] SZ。
        } 
      のためにint型 i = 1 ; iが=分(< 12、SZ [CUR])を、iは++ のための(自動II:ID [i])と
          (ANS [II] + = F [CUR] [II])%= MOD。
      } 
} S、T。
設定 < 整数 > 秒;
INT FA [ 13 ]。
ベクター < INT > D [ 13 ]。
ボイドファック(INT CUR、INT PRE)
{ 
    FA [CUR] = 予備。
    以下のためのint型 I = 1;私は= < 12 ; iは++ 
      Tdの[I] = Dの[I]。
    TN = CUR。
    もし(CUR == 12){T.dfs(10); 返す;}
     int型 X = CUR。
    一方、(X!= 0 
      { 
      D [X] .push_back(CUR + 1 )。
      ファック(CUR + 1 、X)。
      D [X] .pop_back()。
      X = FA [X]。
      } 
} 
int型のmain()
{ 
    ファック(10 );
    以下のためにint型 i = 1 ; iは<= 12 ; I ++ のための(自動J:ID [i])とID [i]の.push_back(J)。
    S.read(); 
    S.DP2(10 );
    int型のトン。
    scanf関数(" %のD "、&T)。
    一方、(t-- 
      { 
      T.read()。
      int型 ANS = 0 ; 
      s.clear(); 
      以下のためにint型 I = 1 ; I <= Tnを、iは++ 
        s.insert(T.dfs(I、0 ))。
      以下のための(自動X:S)(ANS + = S.ans [num_to_id [X]])%= MOD。
      printf(" %d個の\ n " 、ANS)。
      } 
    戻り 0 
}
コードの表示

 

おすすめ

転載: www.cnblogs.com/DeaphetS/p/11260559.html