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;
}

  

BZOJ 3162: 独钓寒江雪 树的同构 + 组合 + 计数的更多相关文章

  1. BZOJ 4337: BJOI2015 树的同构 树hash

    4337: BJOI2015 树的同构 题目连接: http://www.lydsy.com/JudgeOnline/problem.php?id=4337 Description 树是一种很常见的数 ...

  2. BZOJ 4555: [Tjoi2016&Heoi2016]求和 [FFT 组合计数 容斥原理]

    4555: [Tjoi2016&Heoi2016]求和 题意:求\[ \sum_{i=0}^n \sum_{j=0}^i S(i,j)\cdot 2^j\cdot j! \\ S是第二类斯特林 ...

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

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

  4. [BZOJ:3162]:独钓寒江雪

    题解: 求本质不同的独立集的个数 首先独立集的个数是很好做的 \(f[u][0/1]\)表示节点\(u\)不选/选的方案数 然后dp就是 \(f[u][0] = f[u][0] * (f[v][0] ...

  5. BZOJ 2467: [中山市选2010]生成树 [组合计数]

    2467: [中山市选2010]生成树 Time Limit: 5 Sec  Memory Limit: 128 MBSubmit: 638  Solved: 453[Submit][Status][ ...

  6. bzoj 3505 [Cqoi2014]数三角形(组合计数)

    [题目链接] http://www.lydsy.com/JudgeOnline/problem.php?id=3505 [题意] 在n个格子中任选3点构成三角形的方案数. [思路] 任选3点-3点共线 ...

  7. BZOJ 2302: [HAOI2011]Problem c [DP 组合计数]

    2302: [HAOI2011]Problem c Time Limit: 30 Sec  Memory Limit: 256 MBSubmit: 648  Solved: 355[Submit][S ...

  8. bzoj 2281 [Sdoi2011]黑白棋(博弈+组合计数)

    黑白棋(game) [问题描述] 小A和小B又想到了一个新的游戏. 这个游戏是在一个1*n的棋盘上进行的,棋盘上有k个棋子,一半是黑色,一半是白色. 最左边是白色棋子,最右边是黑色棋子,相邻的棋子颜色 ...

  9. BZOJ 4555: [Tjoi2016&Heoi2016]求和 [分治FFT 组合计数 | 多项式求逆]

    4555: [Tjoi2016&Heoi2016]求和 题意:求\[ \sum_{i=0}^n \sum_{j=0}^i S(i,j)\cdot 2^j\cdot j! \\ S是第二类斯特林 ...

随机推荐

  1. vue2.X + HTML5 plus 拍照和调用设备相册 另附 图片转base64和压缩图片方法

    HTML5 部分 <button @click="tesCamera()" type="button" :disabled="isshStatu ...

  2. 【转帖】docker 部署vsftpd服务

    docker 部署vsftpd服务 https://blog.csdn.net/ctwy291314/article/details/82012860 转帖学习一下 docker部署vsftpd服务 ...

  3. 插入数据库失败([Err] 1064 - You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version)

    报错信息如下: , ) 原因,read是数据库的关键字, 牢记,如果一个词是数据库的关键字,那么在写数据库语句的时候,这个词一定是蓝色的(关键字颜色)!!

  4. import和from.…import…

    import和from.-import- 在讲之前我们先来讲一下怎样去下载第三方库,我们把python看作一部手机,pip就是应用管家,第三方库里面的模块就是应用管家里面的一个应用 一.import模 ...

  5. 原生js:click和onclick本质的区别(转https://www.cnblogs.com/web1/p/6555662.html)

    原生javascript的click在w3c里边的阐述是DOM button对象,也是html DOM click() 方法,可模拟在按钮上的一次鼠标单击. button 对象代表 HTML 文档中的 ...

  6. P3964 [TJOI2013]松鼠聚会

    传送门 首先题意就是求一个点到所有其他点的切比雪夫距离和最小 考虑枚举所有点作为答案,那么我们需要快速计算切比雪夫距离和,发现不太好算 根据一些奇怪的套路,我们把坐标系变化,把 $(x,y)$ 变成 ...

  7. python内置下载服务器

    python内置了一个下载服务器.例如你的同事要让你传的文件位于某一个目录下面,那么你可以进入这个目录,然后执行下面的命令启动一个下载服务器 python2 python -m SimpleHTTPS ...

  8. setTimeout定时器

    <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...

  9. JS预解释

    1.声明(declare)  var num   // 告诉浏览器在全局作用域中有一个num变量 定义(defined) num = 12 // 给我们的比变量进行赋值 2.var:在预解释时只是提前 ...

  10. 机器学习-回归中的相关度和R平方值

    1. 皮尔逊相关系数(Pearson Correlation Coefficient) 1.1 衡量两个值线性相关强度的量 1.2 取值范围[-1, 1] 正相关:>0, 负相关:<0, ...