题目链接

题意:
给定一棵无根树,求其中本质不同的独立集的个数。独立集就是一个集合中的点之间都没有边直接相连。n&lt;=5e5n&lt;=5e5n<=5e5,对1e9+71e9+71e9+7取模。

题解:
首先膜拜一下y_immortaly\_immortaly_immortal神仙,是这个神仙教的我这个题怎么做QwQ.

首先考虑没有本质不同应该怎么算。我们设dp[x][0]dp[x][0]dp[x][0]表示考虑xxx为根的子树内不选xxx这个点的方案数,设dp[x][1]dp[x][1]dp[x][1]表示考虑xxx为根的子树内选xxx这个点的方案数。我们枚举xxx的每个子树,我们用子树的方案数乘起来就是答案。dp[x][0]=∏y∈son[x](dp[y][0]+dp[y][1])dp[x][0]=\prod_{y\in son[x]}(dp[y][0]+dp[y][1])dp[x][0]=∏y∈son[x]​(dp[y][0]+dp[y][1]),dp[x][1]=∏y∈son[x]dp[y][0]dp[x][1]=\prod_{y\in son[x]}dp[y][0]dp[x][1]=∏y∈son[x]​dp[y][0]

于是考虑有本质不同怎么来算。我们设dp[x][0]dp[x][0]dp[x][0]表示考虑xxx为根的子树内不选xxx这个点本质不同的独立集数,设dp[x][1]dp[x][1]dp[x][1]表示考虑xxx为根的子树选xxx这个点的本质不同的独立集数。我们把本质相同的树放在一起考虑,我们假设现在考虑到的这种本质相同的子树在xxx的子树中有kkk棵,这种子树的根设为yyy节点。为了保证算方案的时候不会重复,我们给所有yyy中可以的方案编一个号,也就是说yyy子树中有多少种方案,最大的一个编号就是多少。之后我们为了不重复,所有相同的这些子树,规定前面的子树选的编号要小于等于后面的,这样就可以不重不漏。而这个东西应该是一个可重复的组合数。于是我们把每一类本质相同的yyy放在一起算,有dp[x][0]=∏y∈son[x](dp[y][1]+dp[y][0])∗Cdp[y][1]+dp[y][0]+k−1kdp[x][0]=\prod_{y\in son[x]}(dp[y][1]+dp[y][0])*C_{dp[y][1]+dp[y][0]+k-1}^{k}dp[x][0]=∏y∈son[x]​(dp[y][1]+dp[y][0])∗Cdp[y][1]+dp[y][0]+k−1k​ , dp[x][1]=∏y∈son[x]dp[y][0]∗Cdp[y][0]+k−1kdp[x][1]=\prod_{y\in son[x]}dp[y][0]*C_{dp[y][0]+k-1}^{k}dp[x][1]=∏y∈son[x]​dp[y][0]∗Cdp[y][0]+k−1k​

那么下面的问题是如何判断两棵树是否本质相同。我们要做的是树哈希。这里提供一种树哈希的方法。我们设叶子节点的哈希值是111,然后对于其他点,我们把他们的子树按照哈希值排序,然后依次乘进去,乘的时候像字符串哈希那样,把每一个子树看作一个字符,乘一个底数的多少次幂再加进来。最后再乘一个这个子树的size。反正这样起码能保证相同的不会判成不同。

另外就是求组合数的时候,没法求1e9+71e9+71e9+7那么大的,不过我们发现,大部分项可以被约掉,就剩下mmm项,我们暴力算这mmm项就好,我们每个点最多被在组合数里算一次,所以最终还是线性的。

复杂度O(n)O(n)O(n)。

代码:

#include <bits/stdc++.h>
using namespace std;int n,hed[500010],cnt,sz[500010],mx[500010],rt,rt1,rt2,fa[500010];
long long ans,jie[500010],ni[500010],mi[500010],ha[500010],dp[500010][2];
const long long mod=1e9+7,base=23333;
struct node
{int to,next;
}a[2000010];
inline int read()
{int x=0;char s=getchar();while(s>'9'||s<'0')s=getchar();while(s>='0'&&s<='9'){x=x*10+s-'0';s=getchar();}return x;
}
inline long long ksm(long long x,long long y)
{long long res=1;while(y){if(y&1)res=res*x%mod;x=x*x%mod;y>>=1;}return res;
}
inline void add(int from,int to)
{a[++cnt].to=to;a[cnt].next=hed[from];hed[from]=cnt;
}
inline void getrt(int x,int f)
{sz[x]=1;mx[x]=0;for(int i=hed[x];i;i=a[i].next){int y=a[i].to;if(y==f)continue;getrt(y,x);sz[x]+=sz[y];mx[x]=max(sz[y],mx[x]);}mx[x]=max(mx[x],n-sz[x]);if(mx[rt1]>mx[x])rt1=x;else if(mx[x]==mx[rt1])rt2=x;
}
inline void dfs(int x)
{sz[x]=1;for(int i=hed[x];i;i=a[i].next){int y=a[i].to;if(y==fa[x])continue;fa[y]=x;dfs(y);sz[x]+=sz[y];}
}
inline int cmp(int x,int y)
{return ha[x]<ha[y];
}
inline void dfs1(int x)
{int num=0;vector<int> v;v.clear();ha[x]=1;for(int i=hed[x];i;i=a[i].next){int y=a[i].to;if(y==fa[x])continue;dfs1(y);}for(int i=hed[x];i;i=a[i].next){int y=a[i].to;if(y==fa[x])continue;v.push_back(y);++num;}sort(v.begin(),v.end(),cmp);for(int i=0;i<num;++i)ha[x]=(ha[x]+ha[v[i]]*mi[i+1])%mod;ha[x]=ha[x]*sz[x]%mod;
}
inline long long C(int n,int m)
{n%=mod;long long res=1;for(int i=n-m+1;i<=n;++i)res=res*i%mod;res=res*ni[m]%mod;return res;
}
inline void dfs2(int x)
{dp[x][0]=dp[x][1]=1;int num=0;vector<int> v;v.clear();for(int i=hed[x];i;i=a[i].next){int y=a[i].to;if(y==fa[x])continue;dfs2(y);v.push_back(y);++num;}sort(v.begin(),v.end(),cmp);int shu=1;v.push_back(n+2);for(int i=1;i<=num;++i){if(ha[v[i]]!=ha[v[i-1]]){long long qwq=(dp[v[i-1]][0]+dp[v[i-1]][1])%mod,qwqq;qwqq=dp[v[i-1]][0];dp[x][0]=dp[x][0]*C(qwq+shu-1,shu)%mod;dp[x][1]=dp[x][1]*C(qwqq+shu-1,shu)%mod;shu=1;}else++shu;}
}
int main()
{n=read();ha[n+2]=mod+2;for(int i=1;i<=n-1;++i){int x=read(),y=read();add(x,y);add(y,x);}mx[0]=2e9;getrt(1,0);jie[0]=1;for(int i=1;i<=n;++i)jie[i]=jie[i-1]*i%mod;ni[n]=ksm(jie[n],mod-2);for(int i=n-1;i>=0;--i)ni[i]=ni[i+1]*(i+1)%mod;mi[0]=1;for(int i=1;i<=n;++i)mi[i]=mi[i-1]*base%mod;if(mx[rt2]==mx[rt1]){rt=n+1;for(int i=hed[rt1];i;i=a[i].next){int y=a[i].to;if(y==rt2){a[i].to=rt;break;}}for(int i=hed[rt2];i;i=a[i].next){int y=a[i].to;if(y==rt1){a[i].to=rt;break;}}add(rt,rt1);add(rt,rt2);}elsert=rt1;memset(sz,0,sizeof(sz));dfs(rt);dfs1(rt);dfs2(rt);if(rt==rt1){ans=(dp[rt][0]+dp[rt][1])%mod;printf("%lld\n",ans);return 0;}if(ha[rt1]==ha[rt2]){ans=(dp[rt1][0]*dp[rt2][1]%mod+C(dp[rt1][0]+1,2))%mod;printf("%lld\n",ans);}else{ans=(dp[rt1][0]*dp[rt2][1]%mod+dp[rt1][1]*dp[rt2][0]%mod+dp[rt1][0]*dp[rt2][0]%mod)%mod;printf("%lld\n",ans);}return 0;
}

洛谷4895 BZOJ3162 独钓寒江雪 树形dp 树哈希相关推荐

  1. 洛谷 - P4323 [JSOI2016]独特的树叶(树上哈希+换根dp)

    题目链接:点击查看 题目大意:给出一棵 n 个节点的树 A ,再给出一棵 n + 1 个节点的树 B,题目保证了树 B 是树 A 添加了一个叶子结点后的一棵树,只不过编号的顺序不同,现在问这个叶子节点 ...

  2. 洛谷 P1272 重建道路(树形DP)

    P1272 重建道路 题目描述 一场可怕的地震后,人们用N个牲口棚(1≤N≤150,编号1..N)重建了农夫John的牧场.由于人们没有时间建设多余的道路,所以现在从一个牲口棚到另一个牲口棚的道路是惟 ...

  3. 洛谷P3360偷天换日(树形DP)

    题目背景 神偷对艺术馆内的名画垂涎欲滴准备大捞一把. 题目描述 艺术馆由若干个展览厅和若干条走廊组成.每一条走廊的尽头不是通向一个展览厅,就 是分为两个走廊.每个展览厅内都有若干幅画,每副画都有一个价 ...

  4. 洛谷2014 选课(树形DP)树形背包问题

    题目描述 在大学里每个学生,为了达到一定的学分,必须从很多课程里选择一些课程来学习,在课程里有些课程必须在某些课程之前学习,如高等数学总是在其它课程之前学习.现在有N门功课,每门课有个学分,每门课有一 ...

  5. 洛谷P2016 战略游戏 - 树形DP

    一.题目 战略游戏 二.分析 dp1[i] : 第i个节点站士兵,照亮以i为节点的子树所需最少的士兵数: dp0[i] : 第i个节点不站士兵,照亮以i为节点的子树所需最少的士兵数: 状态转移方程: ...

  6. 树形DP+树状数组 HDU 5877 Weak Pair

    1 //树形DP+树状数组 HDU 5877 Weak Pair 2 // 思路:用树状数组每次加k/a[i],每个节点ans+=Sum(a[i]) 表示每次加大于等于a[i]的值 3 // 这道题要 ...

  7. 洛谷 P3373 【模板】线段树 2 题解

    洛谷 P3373 [模板]线段树 2 题解 题面 题目链接:[戳这里](https://www.luogu.org/problemnew/show/P3373) 题目描述 输入输出格式 输入输出样例 ...

  8. 信息学奥赛一本通 1365:FBI树(fbi) | 1928:【04NOIP普及组】FBI树 | 洛谷 P1087 [NOIP2004 普及组] FBI 树

    [题目链接] ybt 1365:FBI树(fbi) ybt 1928:[04NOIP普及组]FBI树 洛谷 P1087 [NOIP2004 普及组] FBI 树 [题目考点] 1. 二叉树 [解题思路 ...

  9. 洛谷4895 独钓寒江雪 (树哈希+dp+组合)

    qwq 首先,如果是没有要求本质不同的话,那么还是比较简单的一个树形dp 我们令dp[i][0/1]dp[i][0/1]dp[i][0/1]表示是否iii的子树,是否选iii这个点的方案数. 一个比较 ...

最新文章

  1. 39个超实用jQuery实例应用特效
  2. (转)CentOS 7系统详细开机启动流程和关机流程
  3. st-link和jlink调试stm32接线注意事项
  4. java利用intellij进行类型推断
  5. 负载(Load)分析及问题排查
  6. android 颜色反转 api,来自Android camera2 API的图像数据在Galaxy S5上翻转和压缩
  7. win7搭建oracle,win7下安装Oracle即时客户端搭建
  8. C语言学习资料和视频
  9. pwn题shellcode收集
  10. linux ll -hrt,Linux col(每日一令之十六)
  11. 基于微信小程序的物流仓储系统
  12. 基于java的网上银行业务
  13. Altium Designer Summer 09快捷键
  14. 跳动公差与其他几何公差(一)
  15. 2021中国市场十大IT热点
  16. 2021计算机考研408计算机学科专业基础综合冲刺复习提纲
  17. 二分查找算法(递归+非递归)
  18. Knights of the Round Table
  19. git 开发分支图解
  20. 微软推送补丁的服务器叫什么,这次就两个!微软推送9月安全补丁

热门文章

  1. VS.net 2005 MFC QQ 2006 TM 2006 消息发送 简单核心代码
  2. PID闭环控制算法解析(最透彻)
  3. 开放源码的 CnPack IDE 专家包发布 0.9.1 版 !
  4. 可视化学习笔记4:使用颜色
  5. 关于NP与co-NP、RP与coRP的理解
  6. android仿微信充值布局,仿微信充值金额输入框-自定义EditText
  7. 水库水位库容监测系统方案
  8. onnx转ncnn的一个坑
  9. 光E电怎样让理财收益最大化
  10. 2021年11月15日到2021年11月21日笔记