Description

Input

Output

求一棵树编号序列不同的方案数:
令 $f[u],g[u]$ 分别表示 $u$ 选/不选 的方案数.
则 $f[u]=\prod_{v\in son[u]}g[v]$,$g[u]=\prod_{v\in son[u]}g[v]+f[v]$.
然而如果要求本质不同,那么那些子树结构相同的就会算重.
假设有 $k$ 个儿子树形态相同,每一个儿子可选的方案为 $h$.
则我们要求给每一个儿子都分一种方案的方案数.
即有 $m$ 个相同的盒子,有 $k$ 种球,求给每一个盒子分配一个球(可重复)的方案数.
这个直接用可重集公式即可,即 $C_{k+m-1}^{m}$.
如何求得所有形态相同得子树呢?
这棵树无论如何旋转,重心都是不变的,以重心(或两重心之间连一个点)为根,进行树哈希+树形DP即可.

#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
#define setIO(s) freopen(s".in","r",stdin)
using namespace std;
typedef long long ll;
const int N=500003,mod=1000000007,mul=20011118,ha=20011118,con=2019;
vector<int>rt;
ll F[N],G[N];
int n,edges,M,root;
int hd[N],to[N<<1],nex[N<<1],mx[N],siz[N],Hash[N],sta[N];
ll qpow(ll base,ll k)
{ll tmp=1ll; for(;k;base=(base*base)%mod,k>>=1) if(k&1) tmp=(tmp*base)%mod;       return tmp;
}
ll inv(int a) { return qpow((ll)a, (ll)mod-2); }
bool cmp(int a,int b)
{return Hash[a]<Hash[b];
}
inline void addedge(int u,int v)
{nex[++edges]=hd[u],hd[u]=edges,to[edges]=v;
}
void getroot(int u,int ff)
{siz[u]=1,mx[u]=0;    for(int i=hd[u];i;i=nex[i]) if(to[i]!=ff) getroot(to[i],u),siz[u]+=siz[to[i]],mx[u]=max(mx[u],siz[to[i]]);       M=min(M,mx[u]=max(mx[u],n-siz[u]));
}
ll C(int a,int b)
{ll tmp=1;    for(int i=a-b+1;i<=a;++i) tmp=(1ll*i*tmp)%mod;      for(int i=1;i<=b;++i) tmp=(1ll*inv(i)*tmp)%mod; return tmp;
}
void calc(int u,int ff)
{ int i,j,tmp=0;                    Hash[u]=2019; for(i=hd[u];i;i=nex[i]) if(to[i]!=ff) calc(to[i],u);          sta[0]=0;            for(i=hd[u];i;i=nex[i]) if(to[i]!=ff) sta[++sta[0]]=to[i];    sort(sta+1,sta+1+sta[0],cmp);    for(i=1;i<=sta[0];++i) Hash[u]=((ll)(Hash[u]*mul)^Hash[sta[i]])%ha;      F[u]=G[u]=1ll;    for(i=1;i<=sta[0];i=j+1) { j=i;   while(j<sta[0]&&Hash[sta[j+1]]==Hash[sta[j]])  ++j;                      F[u]=(F[u]*C(G[sta[i]]+j-i, j-i+1))%mod;       G[u]=(G[u]*C(G[sta[i]]+F[sta[i]]+j-i, j-i+1))%mod;    }
}
int main()
{ int i,j; // setIO("input"); scanf("%d",&n); for(i=1;i<n;++i) {int x,y; scanf("%d%d",&x,&y),addedge(x,y),addedge(y,x);       }M=n,getroot(1,0);      for(i=1;i<=n;++i) if(mx[i]==M) rt.push_back(i);             if(rt.size()==2) { int pre; root=++n;    addedge(n,rt[0]),addedge(n,rt[1]);       if(to[hd[rt[0]]]==rt[1]) hd[rt[0]]=nex[hd[rt[0]]];           else {for(pre=i=hd[rt[0]];i;pre=i,i=nex[i])  if(to[i]==rt[1]) { nex[pre]=nex[i]; break; } }if(to[hd[rt[1]]]==rt[0]) hd[rt[1]]=nex[hd[rt[1]]];           else {for(pre=i=hd[rt[1]];i;pre=i,i=nex[i])  if(to[i]==rt[0]) { nex[pre]=nex[i]; break; } }   }else root=rt[0];  calc(root,0);  if(rt.size()==1) printf("%lld\n",(F[root]+G[root])%mod);    else { int a=rt[0],b=rt[1];    if(Hash[a]==Hash[b]) printf("%lld\n",(G[root]-C(F[a]+1,2)+mod)%mod);   else printf("%lld\n", (((F[a]*F[b])%mod) + ((F[a]*G[b])%mod) + ((G[a]*G[b])%mod)%mod));        }    return 0;
}

  

转载于:https://www.cnblogs.com/guangheli/p/11378318.html

BZOJ 3162: 独钓寒江雪 树的同构 + 组合 + 计数相关推荐

  1. BZOJ 3162 独钓寒江雪(树同构计数)

    给定一棵无根树,求其中本质不同的独立集的个数. 无根树同构. 转化成以重心为根的有根树,如果重心有两个,就在这两个重心之间插入一个点与这两个重心连边,这个点作为新的重心. 然后就成了有根树同构过程树形 ...

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

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

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

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

  4. [树hash]BZOJ 4337——BJOI2015 树的同构

    题目梗概 对于两个树T1和T2,如果能够把树T1的所有点重新标号,使得树T1和树T2完全相 同,那么这两个树是同构的. 有M个有根树,请你把它们按同构关系分成若干个等价类. 解题思路 第一次写树has ...

  5. BZOJ.4337.[BJOI2015]树的同构(树哈希)

    BZOJ 洛谷 \(Description\) 给定\(n\)棵无根树.对每棵树,输出与它同构的树的最小编号. \(n及每棵树的点数\leq 50\). \(Solution\) 对于一棵无根树,它的 ...

  6. BZOJ 4517 浅谈错位排列组合计数

    世界真的很大 讲道理本来5分钟的水题卡了我半个小时一直RE 原因竟是因为cout? 改成printf就对了??EXM? 看题先: description: 求有多少种长度为 n 的序列 A,满足以下条 ...

  7. BZOJ 4337: BJOI2015 树的同构|Hash

    此题三战三卒--!! 一卒:没有考虑连边的顺序. 二卒:用排序解决了连边的顺序,然后用重心似乎搞不了-- 三卒:考虑到rp问题,换了换hash的数..三卒! 扔了重心终于A掉了 可以用括号序列,然后h ...

  8. 【BZOJ - 4337】BJOI2015 树的同构(树哈希)

    题干: 树是一种很常见的数据结构. 我们把N个点,N-1条边的连通无向图称为树. 若将某个点作为根,从根开始遍历,则其它的点都有一个前驱,这个树就成为有根树. 对于两个树T1和T2,如果能够把树T1的 ...

  9. bzoj 4337 树的同构

    4337: BJOI2015 树的同构 Description 树是一种很常见的数据结构. 我们把N个点,N-1条边的连通无向图称为树. 若将某个点作为根,从根开始遍历,则其它的点都有一个前驱,这个树 ...

最新文章

  1. 近期Freecodecamp问题总结
  2. Plant Com:中科院遗传发育所白洋组开发定量检测宿主微生物组的HA-QAP技术(王二涛点评)...
  3. 关于IOCP完成端口的文章
  4. idea无法找到主启动类_idea 启动springboot项目报找不到主类
  5. HotSpot源码(一):Docker与虚拟机的区别,class字节码解析,linux内核源码下载地址,Yacc与Lex快速入门
  6. swift string转int_swift中结构体和类的区别(值类型和引用类型的区别)
  7. java date 时分秒_java Date 获得时分秒代码
  8. python语法学习_python语法学习笔记
  9. javaWeb保存时间到数据库
  10. Android Studio Cmake C++ JNI demo
  11. python程序控制结构与分支的实验报告_Python程序设计实验报告三:分支结构程序设计...
  12. xp计算机位数,XP查看电脑系统版本是32位还是64位的方法
  13. Photoshop CC 2019暂存盘不足无法打开
  14. onkeyup+onafterpaste 只能输入数字和小数点--转载
  15. 视觉SLAM | OKVIS
  16. PTX-NPs 纳米粒子修饰紫杉醇/与桦木酸PEG/邻硝基苯丙酸紫杉醇偶联物的制备
  17. python找与7相关的数字_Python 入门系列 —— 7. 数字类型介绍
  18. 给 木子健康管理室 添加微信公众号 并制作一条 图文消息
  19. 守望先锋服务器修改,守望先锋开发者访谈:关于自定义的服务器
  20. unreal 用于三维展示的改造 建筑 模型展示

热门文章

  1. 咖说 | 揭秘佳士得首次拍卖的区块链艺术品Portraits of a Mind
  2. 等保测评证书是由什么部门发的?申请需要满足什么条件?
  3. FPGA设计开发(基础课题):74LS160计数器芯片设计
  4. 贾跃亭否认乐视IPO造假 为FF融资暂时不会回国
  5. AO是什么?GO是什么?深度解析JS预编译遇见AO和GO
  6. IoT 设备离线时,云端下行消息触达方案
  7. 分析实时嵌入式系统软件调试问题
  8. 这几款软件,你千万别装
  9. java渐进之路(一)基本数据类型与数组
  10. 抖音运营变现必知的几个常识;新手不看后悔一辈子丨国仁网络资讯