给定一棵无根树,求其中本质不同的独立集的个数。
无根树同构。
转化成以重心为根的有根树,如果重心有两个,就在这两个重心之间插入一个点与这两个重心连边,这个点作为新的重心。
然后就成了有根树同构过程树形DP。
这个DP非常naive就不介绍了。
如果子树有kkk个同构,他们的方案数都是ppp
那么我们要本质不同的方案分配,可以想到令给子树分配方案的编号不递减,那么就是每分配给前一个子树一个方案,就要在后面加一个新点来让后面的子树可以和前面的选同一个方案,所以为(p+k−1k)\binom{p+k-1}{k}(kp+k−1​)
ACCode\rm{AC\ Code}AC Code

#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define maxn 500005
#define mod 1000000007
#define LL long long
#define pb push_back
#define pii pair<LL,int>
#define mp make_pair
#define S 131
using namespace std;int Pow(int base,int k){int ret = 1;for(;k;k>>=1,base=1ll*base*base%mod)if(k&1)ret=1ll*ret*base%mod;return ret;
}char cb[1<<16],*cs=cb,*ct=cb;
#define getc() (cs==ct&&(ct=(cs=cb)+fread(cb,1,1<<16,stdin),cs==ct)?0:*cs++)
void read(int &res){char ch;for(;!isdigit(ch=getc()););for(res=ch-'0';isdigit(ch=getc());res=res*10+ch-'0');
}
int n,m,f[maxn][2],siz[maxn];
LL h[maxn];
vector<int>G[maxn],rt;
int Min = 0x3f3f3f3f;
void dfs0(int u,int ff){int Mx = 0;siz[u] = 1;for(int i=0,v;i<G[u].size();i++)if((v=G[u][i])!=ff){dfs0(v,u);siz[u] += siz[v];Mx = max(Mx , siz[v]);}Mx = max(Mx , n - siz[u]);if(Mx < Min) Min = Mx , rt.clear();if(Mx == Min) rt.pb(u);
}
inline bool cmp(const int &u,const int &v){return h[u] < h[v];
}
int invf[maxn];
int C(int n,int m){int ret = 1;for(int i=1;i<=m;i++)ret = 1ll * ret * (n-i+1) % mod;return 1ll * ret * invf[m] % mod;
}
void dfs1(int u,int ff){for(int i=0;i<G[u].size();i++)if(G[u][i] == ff){if(i!=G[u].size()-1)swap(G[u][i],G[u].back());G[u].pop_back() , i--;}else dfs1(G[u][i],u);sort(G[u].begin(),G[u].end(),cmp);h[u] = 3214;f[u][0] = f[u][1] = 1;for(int i=0,j=0;i<G[u].size();i=j){for(j=i;j<G[u].size() && h[G[u][j]] == h[G[u][i]];j++)h[u] = ((h[u] * S) ^ h[G[u][j]]);f[u][0] = 1ll * f[u][0] * C((f[G[u][i]][0]+f[G[u][i]][1]+j-i-1) % mod,j-i) % mod;f[u][1] = 1ll * f[u][1] * C(f[G[u][i]][0]+j-i-1,j-i) % mod;}h[u] *= 1ll * S * S * S;
}int main(){//freopen("1.in","r",stdin);read(n);invf[0] = invf[1] = invf[n] = 1;for(int i=1;i<=n;i++) invf[n] = 1ll * invf[n] * i % mod;invf[n] = Pow(invf[n] , mod-2);for(int i=n-1;i>=2;i--) invf[i] = 1ll * invf[i+1] * (i+1) % mod;for(int i=1,u,v;i<n;i++){read(u),read(v);G[u].pb(v),G[v].pb(u);}dfs0(1,0);int r = rt[0];if(rt.size() == 2){for(int i=0;i<G[rt[0]].size();i++)if(G[rt[0]][i] == rt[1]){if(G[rt[0]].size()-1 != i) swap(G[rt[0]][i],G[rt[0]].back());G[rt[0]].pop_back();}for(int i=0;i<G[rt[1]].size();i++)if(G[rt[1]][i] == rt[0]){if(G[rt[1]].size()-1 != i) swap(G[rt[1]][i],G[rt[1]].back());G[rt[1]].pop_back();}G[++n].pb(rt[0]),G[n].pb(rt[1]);r = n;}dfs1(r,0);printf("%lld\n",(f[r][0] + (rt.size()==1 ? f[r][1] : -(h[rt[0]] == h[rt[1]] ? C(f[rt[0]][1]+1,2) : f[rt[0]][1] * 1ll * f[rt[1]][1] % mod)) % mod + mod) % mod);
}

BZOJ 3162 独钓寒江雪(树同构计数)相关推荐

  1. BZOJ 3162: 独钓寒江雪 树的同构 + 组合 + 计数

    Description Input Output 求一棵树编号序列不同的方案数: 令 $f[u],g[u]$ 分别表示 $u$ 选/不选 的方案数. 则 $f[u]=\prod_{v\in son[u ...

  2. bzoj 3162: 独钓寒江雪 树哈希+树形dp

    题意 给出一棵无标号无根树,问本质不同的最大独立集数量.答案模1e9+7. n<=500000 分析 对于一般的情况,我们可以先找出树的重心作为根,然后进行树形dp.这样做有什么好处呢?通过根的 ...

  3. bzoj 1211 [HNOI2004]树的计数

    [HNOI2004]树的计数 Description 一个有n个结点的树,设它的结点分别为v1, v2, -, vn,已知第i个结点vi的度数为di,问满足这样的条件的不同的树有多少棵.给定n,d1, ...

  4. BZOJ 1211: [HNOI2004]树的计数 purfer序列

    1211: [HNOI2004]树的计数 Description 一个有n个结点的树,设它的结点分别为v1, v2, -, vn,已知第i个结点vi的度数为di,问满足这样的条件的不同的树有多少棵.给 ...

  5. BZOJ 3244: [Noi2013]树的计数

    传送门 神仙题... 和树的深度有关,由于 $BFS$ 序的性质,显然可以通过把 $BFS$ 序分成若干段来求出深度,每一段就对应某一深度从左到右的所有节点,那么如果确定了分的段数就确定了树的深度(分 ...

  6. 无根树的同构:Hash最小表示法(bzoj 4337: BJOI2015 树的同构)

    这里的同构是指: 对于两棵树A, B,如果能通过重新标号使得两棵树完全相同,则称树A和B同构 Hash最小表示法步骤: ①暴力每个节点为根 ②对于当前根x,对树进行DFS ③DFS时对每个节点维护一个 ...

  7. 树的计数 Prüfer编码与Cayley公式 学习笔记

    最近学习了Prüfer编码与Cayley公式,这两个强力的工具一般用于解决树的计数问题.现在博主只能学到浅层的内容,只会用不会证明. 推荐博客:https://blog.csdn.net/moreja ...

  8. BZOj #4771. 七彩树(主席树+dfn序+lca)

    BZOj #4771. 七彩树 description solution code description 给定一棵n个点的有根树,编号依次为1到n,其中1号点是根节点.每个节点都被染上了某一种颜色, ...

  9. 【BZOJ1211】【HNOI2004】树的计数(prufer序,组合数)

    Description 一个有n个结点的树,设它的结点分别为v1, v2, -, vn,已知第i个结点vi的度数为di,问满足这样的条件的不同的树有多少棵.给定n,d1, d2, -, dn,编程需要 ...

最新文章

  1. Swift - 使用 Protocol 避免框架之间循环引用
  2. Aduna ClusterMap 的说明
  3. gdb+pwndbg使用初探
  4. [网络安全自学篇] 六十四.Windows安全缺陷利用之SMBv3服务远程代码执行(CVE-2020-0796)复现及防御机理
  5. image vb6 图片自适应_请问如何实现图片在窗体上的大小自适应?
  6. python桌面翻译_Python实现桌面翻译工具【新手必学】
  7. IDEA调整输出字体的字体与大小
  8. 超市也开始玩“内卷”?
  9. Google、Facebook等不可错过的 AI 开源工具,你想要的都在这里!
  10. etl 不能转换成date_java怎么将date类型转换成datetime类型
  11. 如何使用python批量压缩图片_利用Python 批量压缩图片
  12. 如何关闭Steam的弹出广告
  13. NCU SEM 发文检索2014年
  14. Win10笔记本开启热点让手机上网
  15. android+注册+代码,简单的Android用户注册登录实现
  16. 当页面放大后, 背景会消失
  17. 机载LIDAR技术及其应用
  18. poi向excel插入图片demo
  19. table表格五星好评的实现
  20. 调用CachedRowSetImpl类时出现错误

热门文章

  1. C语言试题151之求 0到7 所能组成的奇数个数。
  2. zabbix接合grafana画图
  3. c++怎么确定一个整数有几位_德国人怎么学电机——浅谈电机模型(十六):同步电机(三)永磁电机(一)...
  4. IoT 设备接入服务,你从这篇博客就能快速上手~
  5. LiDAR 5 相控阵激光雷达 (OPA LiDAR)
  6. CF #669 (Div. 2)D. Discrete Centrifugal Jumps(线段树/单调队列优化dp)
  7. iOS开发——播放系统音效、自定义音效
  8. process_vm_readv/writev进程间数据传输
  9. android学习笔记(2)--RxJava
  10. 计算机二级可以抵消计算机挂科吗,妈妈再也不用担心我挂科啦!| 计算机二级office考试...