bzoj
忽然翻到這道題目,突然發現就是前幾天一道考試題目。。。
題解:
樹雜湊,既然只考慮這一棵樹,那麼,如果兩個點為根是同構的,
他們的重心相同,所以直接找出樹的重心,以重心為根進行轉移
提前預處理每一棵子樹的雜湊值,因為相同的子樹是同構的,所以轉移相當於是可重組合的計算。
對於存在兩個重心的情況,分兩個重心的子樹同構還是不同構。
如果不同構則隨便選擇乙個重心即可。如果同構,則建立乙個虛點,然後dp
d
p最後容斥一下即可。
中間算組合數的時候,發現只與兒子個數有關,所以可以爆算。
#include
#include
#include
#include
#include
#include
using
namespace
std;
#define ull unsigned long long
#define ll long long
#define rg register
#define max 500500
#define mod 1000000007
#define inv2 500000004
inline
int read()
void add(int &x,int y)
struct linee[max<<1];
int h[max],cnt=2;
inline
void add(int u,int v);h[u]=cnt++;}
int f[max][2],ans,n,size[max],rt,rt2,s[max],top,msz[max];
const ull base1=19;
const ull base2=19260817;
const ull base3=1e16+5;
ull hash[max];
int jc[max],jv[max],inv[max];
bool cmp(int a,int b)
void getroot(int u,int ff)
msz[u]=max(msz[u],n-size[u]);
if(msz[u]else
if(msz[u]==msz[rt])rt2=u;
}void dfs(int u,int ff)
}void gethash(int u,int ff)
hash[u]+=base2*size[u]+base3*son*son*size[u];
}int main()
for(int i=2;i<=n;++i)inv[i]=1ll*inv[mod%i]*(mod-mod/i)%mod;
for(int i=1;i<=n;++i)jc[i]=1ll*jc[i-1]*i%mod;
for(int i=1;i<=n;++i)jv[i]=1ll*jv[i-1]*inv[i]%mod;
getroot(1,0);
if(msz[rt]==msz[rt2])
else
dfs(n+1,0);ans=c(f[rt][1]+1,2);ans=mod-ans;add(ans,f[n+1][0]);}}
else gethash(rt,0),dfs(rt,0),ans=(f[rt][0]+f[rt][1])%mod;
printf("%d\n",ans);
return
0;}
BZOJ3162 獨釣寒江雪
bzoj 你要給乙個樹上的每個點黑白染色,要求白點不相鄰。求本質不同的染色方案數。兩種染色方案本質相同當且僅當對樹重新標號後對應節點的顏色相同。n le 5 times10 5 首先考慮沒有本質相同那個限制怎麼做。直接設 f 表示 i 點染成黑色 白色時子樹內的方案數。轉移很簡單 f prod j ...
BZOJ 3162 獨釣寒江雪
題意是求一棵無根樹本質不同獨立集的個數 那個所謂 極寒點 的選取就是獨立集。結構相同就是樹同構,完全相同就是樹的形態和獨立集都相同。我們先求出樹的重心,就可以轉化為有根樹同構問題。令 f u 1 為在 u 的子樹中,選取 u 的方案樹,f u 0 為在 u 的子樹中,不選取 u 的方案數。得到最基本...
BZOJ3162 獨釣寒江雪 樹同構 DP
題解 先進行樹hash,方法是找重心,如果重心有兩個,則新建乙個虛點將兩個重心連起來,新點即為新樹的重心。將重心當做根進行hash,hash函式不能太簡單,我的方法是 將x的所有兒子的hash值排序,然後將這些hash值立方合在一起作為x的hash值。進行完樹hash後,我們考慮dp。首先不考慮同構...