BZOJ 3162 獨釣寒江雪

2022-05-01 04:21:07 字數 1936 閱讀 8601

題意是求一棵無根樹本質不同獨立集的個數

那個所謂「極寒點」的選取就是獨立集。

結構相同就是樹同構,完全相同就是樹的形態和獨立集都相同。

我們先求出樹的重心,就可以轉化為有根樹同構問題。

令$f[u][1]$為在$u$的子樹中,選取$u$的方案樹,$f[u][0]$為在$u$的子樹中,不選取$u$的方案數。

得到最基本的dp方程:

$f[u][0]=\prod_(f[v][0]+f[v][1])$

$f[u][1]=\prod_f[v][0]$

但是可能出現直徑長為奇數的情況,需要分類討論。

判斷樹同構用雜湊亂搞就好了。

1 #include 2 #include 3 #include 

4 #include 5

using

namespace

std;

6#define maxn 500010

7#define mod 1000000007

8#define p1 2150527

9#define p2 1231231237

10#define ll long long

11 inline int

read()

1221

while(ch>='

0'&&ch<='9'

)22 s=s*10+ch-'

0',ch=getchar();

23return s*f;24}

25struct

edge

26e[maxn<<1

];29

int pr[maxn],cnt=1;30

intsiz[maxn];

31void add(int u,int

v)32

;34 pr[u]=cnt;

35 e[++cnt]=(edge);

36 pr[v]=cnt;37}

38int rt[2

],root;

39ll inv[maxn];

40ll haha[maxn];

41 ll f[maxn][2

];42

intst[maxn];

43bool cmp(int a,int

b)44

47 ll c(int n,int

m)48

54void dp(int u,int

fa)55

74for(i=1;i<=top;i++)

75 haha[u]=haha[u]*p1+(haha[st[i]]+i)*p2;76}

77int

n;78

void dfs(int u,int

fa)7993}

94if((siz[u]<<1)

95 flag=0;96

if(flag)

97103

}104

void

init()

105110

intmain()

111121 dfs(1,0

);122

if(rt[1

])123

131 add(root,rt[0

]);132 add(root,rt[1

]);133

}134

else

135 root=rt[0

];136 dp(root,0

);137

if(!rt[1

])138 printf("

%lld

",(f[root][0]+f[root][1])%mod);

139else

140148 }

bzoj 3162

BZOJ3162 獨釣寒江雪

bzoj 你要給乙個樹上的每個點黑白染色,要求白點不相鄰。求本質不同的染色方案數。兩種染色方案本質相同當且僅當對樹重新標號後對應節點的顏色相同。n le 5 times10 5 首先考慮沒有本質相同那個限制怎麼做。直接設 f 表示 i 點染成黑色 白色時子樹內的方案數。轉移很簡單 f prod j ...

BZOJ3162 獨釣寒江雪 樹同構 DP

題解 先進行樹hash,方法是找重心,如果重心有兩個,則新建乙個虛點將兩個重心連起來,新點即為新樹的重心。將重心當做根進行hash,hash函式不能太簡單,我的方法是 將x的所有兒子的hash值排序,然後將這些hash值立方合在一起作為x的hash值。進行完樹hash後,我們考慮dp。首先不考慮同構...

BZOJ3162 獨釣寒江雪(雜湊 樹形dp)

數獨立集顯然是可以樹形dp的,問題在於本質不同。假設已經給樹確立了乙個根並且找到了所有等效 注意是等效而不是同構 子樹,那麼對轉移稍加修改使用隔板法就行了。關鍵在於找等效子樹。首先將樹的重心 若有兩個則加乙個點作為唯一重心 作為根。這樣任意極大等效子樹 比如某兩個等效子樹裡面的一部分等效,那麼裡面這...