問題の意味:木の少しの権利を与えられたが、ブロックの数は尋ね伝えた製品<= M; N <= 2000 、M <1E6;
考える:通信ブロック- >パーティション;一般的なツリーをMの複雑さは、依存バックパックでそうするときDPの合併が高くなりますので。(もちろん、体積分布は離散的であるため、一部のプレーヤーは、このように(I、1、M)毎の時間を避けて、地図上にも使用することができる 、 データ、それに応じて)。
だから今の複雑さはO(NlogN * M)で、スペースはまだ最適化されるように、O(N * M)です。
<SQRT(M)に非常に巧妙な(M)SQRTよりも大きい場合、別途ここに格納され、その後、前者は通常のバックパックで、バックパックは、多くのものに格納されていたと述べ、後者はまた、あなたが保存することができますどのくらいのバックパックアップとして見ることができます。スペースO(Nsqrt(M));次に、複雑さはO(Nsqrt(M)logN個)となる渡すことができます。
#include <ビット/ STDC ++ H> の#define担当者(iは、B)(iは= int型、iが= Bを<; I ++の)のため の#defineは長い長いllの 使用 名前空間STDを、 const int型 MAXN = 2010 ; const int型のMod = 1E9 + 7 。 INT [MAXN、W、ANS。 INT DP1 [MAXN] [MAXN >> 1 ]、DP2 [MAXN] [MAXN >> 1 ]、DP [MAXN] [MAXN]。 INT Laxt [MAXN]、次に[MAXN << 1 ]、[MAXN <<に1 ]、CNT。 int型の息子を[MAXN]、SZ [MAXN]、VIS [MAXN]、RT、SZ。 int型回、P [MAXN]、M、QM; 空 MOD(INT&X){ 場合(X> MOD)X- = モッド;} ボイド追加(INT U、INT V) { 次に[ ++ CNT] = Laxt [U]。Laxt [U] = CNT。[CNT] =にV。 } ボイド getroot(INT U、INT F)// 得到重心 { SZ [U] = 1。息子[U] = 0 ; 用(int型 I = Laxt [U]; I; I = 次に[I]){ int型 V =に、[I]。もし(VIS [V] || V == f)の続けます。 getroot(V、U); SZ [U] + =SZ [V]。 息子[U] = MAX(息子[U]、SZ [V])。 } 息子[U] = MAX(息子[U]、SZ- 息子[U])。 もし(室温== 0 ||息子[U] <息子[RT])RT = U。 } ボイド DFS(INT U、INT F)// 得到DFS序。 { P [ ++回] = U。SZ [U] = 1 。 以下のために(int型 I = Laxt [U]; I; I = 次に[I]){ 場合(TO [I] == F || VIS [i]は[へ])続けます。 DFS([I]、Uへ)。 SZ [U] + = SZ [I]へ]。 } } ボイドCAL() { 担当者(I、1、回+ 1 ){ memsetの(DP1 [i]は、0、はsizeof (DP1 [I]))。 memsetの(DP2 [i]は、0、はsizeof (DP2 [I]))。 } DP1 [回 + 1 ] [ 1 ] = 1 。 以下のために(int型 =回Iを、I> = 1 ; i-- ){ int型、X = W [P [I]]。 担当者(J、1、分(QM、M / X)){ int型のk = j個*のX。 もし(K <= QM)MOD(DP1 [I] [K] + = DP1 [I + 1 ] [J])。 他の MOD(DP2 [I] [M / K] + = DP1 [I + 1 ] [J])。 } 担当者(J、X、QM){ MOD(DP2 [I]、[J / X] + = DP2 [I + 1 ] [J])。 } 担当者(J、1、QM)MOD(DP1 [I] [J] + = DP1 [iが+ SZ [Pを[I]]] [J])。 担当者(J、1、QM)MOD(DP2 [I] [J] + = DP2 [iが+ SZ [Pの【をI]]] [J])。 } 担当者(I、1、QM)MOD(ANS + = DP1 [ 1 ] [I])。 担当者(I、1、QM)MOD(ANS + = DP2 [ 1 ] [I])。 ANS - ; //减去为空的情况 場合(ANS < 0)ANS + = モッド。 } ボイドが解決する(INT U)// 分治 { VIS [U] = 1 。 時間 = 0 ; DFS(U、0 ); CAL(); 用(int型 I = Laxt [U]; I; I = 次に[I]){ 場合(VIS [i]が[へ])続けます。 SZ = SZ [I] [へ]。RT = 0 ; ([I]にgetroot 0 )。 (RT)を解きます。 } } int型)(主 { int型のT、N、U、V。 scanf関数(" %のD "、&T)。 一方、(T-- ){ scanf関数(" %d個の%のD "、&N、&M)。QM = SQRT(M)。 担当者(I、1、N)のscanf(" %dの"、&W [I])。 担当者(I、1、N)Laxt [I] = VIS [I] = 0 ; CNT = 0 ; 担当者(I、1、N- 1 ){ scanf関数(" %D%dの"、&U、およびV)。 (V、U)を追加します。(V、U)を追加。 } SZ = N。RT =0。getroot(1、0 ); ANS = 0 ; (RT)を解きます。 printf(" %d個の\ n " 、ANS)。 } 戻り 0 。 }