版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
题目描述:
给定一棵无根树,求其中本质不同的独立集的个数。
n<=500000
题目分析:
如果任选一点作根,那么它选1的情况和它选0的情况有可能是本质相同的。
但如果选重心作根(如果有两个重心,就新建一个点连向两个重心,原来的边断掉),那么它选1的情况和它选0的情况一定是本质不同的。
我们不难看出重心是树中唯一确定的点,没有任何一点能够与它等价。
所以用重心作根,
表示子树方案数,子树按照哈希值排序,dp即可。
对于同构的
个儿子,如果他们的方案为
,要让它们不重复,就把方案编号然后由小到大取,可以看做把
个球放入
个盒子中,盒子可以为空的方案数,答案是
。由于k<mod,所以由lucas可知组合数的上半部分是可以模的。
Code:
#include<bits/stdc++.h>
#define maxn 500005
using namespace std;
typedef unsigned long long ULL;
const int mod = 1e9+7;
const ULL Seed = 19260817;
int n,rt[3],inv[maxn],f[maxn][2],son[maxn],H[maxn];
int fir[maxn],nxt[maxn<<1],to[maxn<<1],tot;
inline void line(int x,int y){nxt[++tot]=fir[x],fir[x]=tot,to[tot]=y;}
int getroot(int u,int ff){
int siz=1,tmp; bool flg=1;
for(int i=fir[u];i;i=nxt[i]) if(to[i]!=ff){
siz+=(tmp=getroot(to[i],u));
if(tmp<<1>n) flg=0;
}
if((n-siz)<<1>n) flg=0;
if(flg) rt[++rt[0]]=u;
return siz;
}
bool cmp(int i,int j){return H[i]<H[j];}
inline int C(int n,int m){
int ret=1;
while(m) ret=1ll*ret*(n--)%mod*inv[m--]%mod;
return ret;
}
void dfs(int u,int ff){
f[u][0]=f[u][1]=1;
for(int i=fir[u];i;i=nxt[i]) if(to[i]!=ff) dfs(to[i],u);
int cnt=0;
for(int i=fir[u];i;i=nxt[i]) if(to[i]!=ff) son[++cnt]=to[i];
sort(son+1,son+1+cnt,cmp);
H[u]=23333;
for(int i=1,j,v;i<=cnt;i=j){
for(v=son[j=i];j<=cnt&&H[son[j]]==H[v];j++) H[u]=H[u]*Seed^H[son[j]];
f[u][0]=1ll*f[u][0]*C(f[v][0]+f[v][1]+j-i-1,j-i)%mod;
f[u][1]=1ll*f[u][1]*C(f[v][0]+j-i-1,j-i)%mod;
}
H[u]*=Seed*Seed;
}
int main()
{
int x,y,r;
scanf("%d",&n);
for(int i=1;i<n;i++) scanf("%d%d",&x,&y),line(x,y),line(y,x);
inv[0]=inv[1]=1;
for(int i=2;i<=n;i++) inv[i]=1ll*(mod-mod/i)*inv[mod%i]%mod;
getroot(1,0);
if(rt[0]>1){
r=n+1;
for(int i=fir[rt[1]];i;i=nxt[i]) if(to[i]==rt[2]) {to[i]=r;break;}
for(int i=fir[rt[2]];i;i=nxt[i]) if(to[i]==rt[1]) {to[i]=r;break;}
line(r,rt[1]),line(r,rt[2]);
}
else r=rt[1];
dfs(r,0);
if(rt[0]>1) printf("%d\n",(H[rt[1]]==H[rt[2]]?C(f[rt[1]][0]+1,2)+1ll*f[rt[1]][1]*f[rt[1]][0]:f[r][0]-1ll*f[rt[1]][1]*f[rt[2]][1]%mod+mod)%mod);
else printf("%d\n",(f[r][0]+f[r][1])%mod);
}