独钓寒江雪
Description
给定一棵无根树,求其中本质不同的独立集的个数。
注:本质不同是指树的同构不同。
Solution
tag : 树哈希,dp
无根树不好处理,先讨论有根树的情况。
设 \(dp_{u,0/1}\) 是以 \(u\) 为根的有根树,该节点不选/选的方案数,转移简单。
但是当子树 \(u\) 有两个同构的子树时,若两个子树的独立集相同就会算重。
所以考虑使用树哈希,找到所有同构的子树,分别使用组合数处理,发现类似插板法。
然后钦定重心为根,转换为有根树处理。
当重心为一个点时,答案就是 \(dp_{rt,0} + dp_{rt,1}\)。
当重心为一条边(有两个重心)时,分类讨论两个子树是否同构:
-
若不同构,答案显然为 \(dp_{x,0} \times dp_{y,0} + dp_{x,1} \times dp_{y,0} + dp_{x,0} \times dp_{y,1}\),其中 \(x\) 和 \(y\) 分别为两个重心。
-
若同构,答案要在上式的基础上还要减去两个子树相同情况,就是 \(dp_{rt,0} \times dp_{rt,1} + \dfrac{dp_{rt,0}^2 + dp_{rt,0}}{2}\)。
注意哈希处理得不好容易被卡,我的方法是把素数表随机打乱。
点击查看代码
#include<bits/stdc++.h>
#define FASTIO ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
#define ull unsigned long long
#define int long long
#define rep(i,l,r) for(int i=(l); i<=(r); ++i)
#define drep(i,r,l) for(int i=(r); i>=(l); --i)
using namespace std;
const int N=5e5+5,M=7368787,mod=1e9+7;
int n,x,y,tot,p[N],sz[N],dp[N][2],inv[N];
bool vis[M+5];
vector<int>rt,G[N];
ull h[N];
inline int C(int x,int y,int res=1) {
rep(i,x-y+1,x) (res*=i)%=mod;
rep(i,1,y) (res*=inv[i])%=mod;
return res;
}
inline void dfs(int x,int fa,int mx=0) {
sz[x]=1;
for(auto y:G[x]) if(y^fa) dfs(y,x),sz[x]+=sz[y],mx=max(mx,sz[y]);
if(max(mx,n-sz[x])<=n/2) rt.push_back(x);
}
inline void dfs2(int x,int fa) {
unordered_map<int,int>cnt,mp;
h[x]=sz[x]=dp[x][0]=dp[x][1]=1;
for(auto y:G[x]) if(y^fa) dfs2(y,x),sz[x]+=sz[y],h[x]+=h[y]*p[sz[y]],cnt[h[y]]++,mp[h[y]]=y;
for(auto [v,c]:cnt) {
int y=mp[v];
dp[x][0]=dp[x][0]*C(dp[y][0]+dp[y][1]+c-1,c)%mod;
dp[x][1]=dp[x][1]*C(dp[y][0]+c-1,c)%mod;
}
}
signed main() {
FASTIO;
cin>>n,inv[1]=1;
rep(i,2,n) cin>>x>>y,G[x].push_back(y),G[y].push_back(x);
rep(i,2,n) inv[i]=mod-mod/i*inv[mod%i]%mod;
rep(i,2,M) if(!vis[i]) {
p[++tot]=i;
rep(j,2,M/i) vis[i*j]=1;
}
random_shuffle(p+1,p+tot+1);
dfs(1,0);
if(rt.size()==1) dfs2(rt[0],0),cout<<(dp[rt[0]][0]+dp[rt[0]][1])%mod,exit(0);
else {
dfs2(rt[0],rt[1]),dfs2(rt[1],rt[0]);
if(h[rt[0]]==h[rt[1]]) cout<<(dp[rt[0]][0]*dp[rt[0]][1]+C(dp[rt[0]][0]+1,2))%mod;
else cout<<(dp[rt[0]][0]*dp[rt[1]][0]+dp[rt[0]][1]*dp[rt[1]][0]+dp[rt[0]][0]*dp[rt[1]][1])%mod;
}
}
浙公网安备 33010602011771号