数独立集显然是可以树形dp的,问题在于本质不同。

  假设已经给树确立了一个根并且找到了所有等效(注意是等效而不是同构)子树,那么对转移稍加修改使用隔板法就行了。

  关键在于找等效子树。首先将树的重心(若有两个则加一个点作为唯一重心)作为根。这样任意极大等效子树(比如某两个等效子树里面的一部分等效,那么里面这一部分就不是极大的)一定有相同的父亲,否则我们所选的根是肯定存在一棵子树大小大于树的一半的,与重心性质矛盾。那么判等效就只需要考虑子树内同构了。

  同构判断采取哈希。这里使用最简单的类似字符串哈希的做法,用子树大小哈希。在保证同构树哈希值相同的前提下尽量增加变数。

  1. #include<iostream>
  2. #include<cstdio>
  3. #include<cmath>
  4. #include<cstdlib>
  5. #include<cstring>
  6. #include<algorithm>
  7. using namespace std;
  8. int read()
  9. {
  10. int x=,f=;char c=getchar();
  11. while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
  12. while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
  13. return x*f;
  14. }
  15. #define N 500010
  16. #define P 1000000007
  17. #define ul unsigned long long
  18. int n,p[N],p_new[N],f[N][],size[N],q[N],inv[N],root,t=;
  19. ul hash[N];
  20. struct data{int to,nxt;
  21. }edge[N<<],edge_new[N<<];
  22. void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
  23. void addedge_new(int x,int y){t++;edge_new[t].to=y,edge_new[t].nxt=p_new[x],p_new[x]=t;}
  24. void dfs(int k,int from)
  25. {
  26. size[k]=;
  27. for (int i=p[k];i;i=edge[i].nxt)
  28. if (edge[i].to!=from)
  29. {
  30. dfs(edge[i].to,k);
  31. size[k]+=size[edge[i].to];
  32. }
  33. }
  34. void dfs2(int k,int from)
  35. {
  36. for (int i=p[k];i;i=edge[i].nxt)
  37. if (edge[i].to!=from)
  38. {
  39. addedge_new(k,edge[i].to);
  40. dfs2(edge[i].to,k);
  41. }
  42. }
  43. int findroot(int k,int from)
  44. {
  45. int mx=;
  46. for (int i=p[k];i;i=edge[i].nxt)
  47. if (edge[i].to!=from&&size[edge[i].to]>size[mx]) mx=edge[i].to;
  48. if ((size[mx]<<)<=n) return k;
  49. else return findroot(mx,k);
  50. }
  51. int C(int n,int m)
  52. {
  53. int ans=;
  54. for (int i=n;i>=n-m+;i--) ans=1ll*ans*i%P;
  55. return 1ll*ans*inv[m]%P;
  56. }
  57. bool cmp(const int&a,const int&b)
  58. {
  59. return hash[a]<hash[b];
  60. }
  61. void gethash(int k)
  62. {
  63. int cnt=;
  64. for (int i=p[k];i;i=edge[i].nxt)
  65. q[++cnt]=hash[edge[i].to];
  66. sort(q+,q+cnt+);
  67. for (int i=;i<=cnt;i++) hash[k]=hash[k]*+q[i];
  68. hash[k]=(hash[k]*+size[k])%P;
  69. }
  70. void dp(int k)
  71. {
  72. for (int i=p[k];i;i=edge[i].nxt)
  73. dp(edge[i].to),gethash(edge[i].to);
  74. int cnt=;
  75. for (int i=p[k];i;i=edge[i].nxt)
  76. q[++cnt]=edge[i].to;
  77. sort(q+,q+cnt+,cmp);
  78. f[k][]=f[k][]=;
  79. for (int i=;i<=cnt;i++)
  80. {
  81. int t=i;
  82. while (t<cnt&&hash[q[t+]]==hash[q[i]]) t++;
  83. f[k][]=1ll*f[k][]*C(f[q[i]][]+t-i,t-i+)%P;
  84. f[k][]=1ll*f[k][]*C(f[q[i]][]+f[q[i]][]+t-i,t-i+)%P;
  85. i=t;
  86. }
  87. }
  88. int main()
  89. {
  90. #ifndef ONLINE_JUDGE
  91. freopen("bzoj3162.in","r",stdin);
  92. freopen("bzoj3162.out","w",stdout);
  93. const char LL[]="%I64d\n";
  94. #else
  95. const char LL[]="%lld\n";
  96. #endif
  97. n=read();
  98. inv[]=inv[]=;for (int i=;i<=n;i++) inv[i]=P-1ll*(P/i)*inv[P%i]%P;
  99. for (int i=;i<=n;i++) inv[i]=1ll*inv[i]*inv[i-]%P;
  100. for (int i=;i<n;i++)
  101. {
  102. int x=read(),y=read();
  103. addedge(x,y),addedge(y,x);
  104. }
  105. dfs(,);
  106. root=findroot(,);
  107. dfs(root,root);
  108. int v=;
  109. for (int i=p[root];i;i=edge[i].nxt)
  110. if (!(n&)&&size[edge[i].to]==(n>>)) {v=edge[i].to;break;}
  111. t=;
  112. if (v)
  113. {
  114. n++;dfs2(root,v);dfs2(v,root);
  115. addedge_new(n,root),addedge_new(n,v);root=n;
  116. }
  117. else dfs2(root,root);
  118. memcpy(p,p_new,sizeof(p));
  119. memcpy(edge,edge_new,sizeof(edge));
  120. dfs(root,root);
  121. dp(root);
  122. if (v)
  123. {
  124. int x=edge[p[root]].to,y=edge[edge[p[root]].nxt].to;
  125. if (hash[x]==hash[y])
  126. f[root][]=(C(f[x][]+,)+1ll*f[x][]*f[x][]%P)%P;
  127. else f[root][]=(1ll*f[x][]*(f[y][]+f[y][])%P+1ll*f[x][]*f[y][]%P)%P;
  128. f[root][]=;
  129. }
  130. cout<<(f[root][]+f[root][])%P;
  131. return ;
  132. }

BZOJ3162 独钓寒江雪(哈希+树形dp)的更多相关文章

  1. [bzoj3162]独钓寒江雪_树hash_树形dp

    独钓寒江雪 题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=3162 题解: 首先,如果没有那个本质相同的限制这就是个傻逼题. 直接树形dp ...

  2. BZOJ_3573_[Hnoi2014]米特运输_树形DP+hash

    BZOJ_3573_[Hnoi2014]米特运输_树形DP+hash 题意: 给你一棵树每个点有一个权值,要求修改最少的权值,使得每个节点的权值等于其儿子的权值和且儿子的权值都相等. 分析: 首先我们 ...

  3. 树形DP(记忆化搜索) HYSBZ - 1509

    题目链接:https://vjudge.net/problem/HYSBZ-1509 我参考的证明的论文:8.陈瑜希<多角度思考 创造性思维>_百度文库  https://wenku.ba ...

  4. poj3417 LCA + 树形dp

    Network Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 4478   Accepted: 1292 Descripti ...

  5. COGS 2532. [HZOI 2016]树之美 树形dp

    可以发现这道题的数据范围有些奇怪,为毛n辣么大,而k只有10 我们从树形dp的角度来考虑这个问题. 如果我们设f[x][k]表示与x距离为k的点的数量,那么我们可以O(1)回答一个询问 可是这样的话d ...

  6. 【BZOJ-4726】Sabota? 树形DP

    4726: [POI2017]Sabota? Time Limit: 20 Sec  Memory Limit: 128 MBSec  Special JudgeSubmit: 128  Solved ...

  7. 树形DP+DFS序+树状数组 HDOJ 5293 Tree chain problem(树链问题)

    题目链接 题意: 有n个点的一棵树.其中树上有m条已知的链,每条链有一个权值.从中选出任意个不相交的链使得链的权值和最大. 思路: 树形DP.设dp[i]表示i的子树下的最优权值和,sum[i]表示不 ...

  8. 树形DP

    切题ing!!!!! HDU  2196 Anniversary party 经典树形DP,以前写的太搓了,终于学会简单写法了.... #include <iostream> #inclu ...

  9. BZOJ 2286 消耗战 (虚树+树形DP)

    给出一个n节点的无向树,每条边都有一个边权,给出m个询问,每个询问询问ki个点,问切掉一些边后使得这些顶点无法与顶点1连接.最少的边权和是多少.(n<=250000,sigma(ki)<= ...

随机推荐

  1. Python学习过程笔记整理(四)

    变量作用域 -分类 -全局(global):在函数外部定义:整个全局范围都有效 -局部(local):在函数内部定义:仅在局部范围有效 -提升局部变量为全局变量 -使用global -globals, ...

  2. redmine on centos

    一 前言 前前后后搭建redmine,花费了很多时间.期间会遇到各种坑,因此总结下自己的方法,分享给各位童鞋. 二 操作系统  centos release 6.9 详细信息如下图:   三 安装步骤 ...

  3. 【SIKIA计划】_06_Unity2D游戏开发-拾荒者笔记

    [新增分类]Animations 动画——Animation——AnimatorControllerPrefabs 预制 [素材导入]unitypackage 素材包Sprites Editor 编辑 ...

  4. NAT概念解释(不完全版,但不会搞错...)

    NAT在计算器网络中,网络地址转换(Network Address Translation,缩写为NAT),也叫做网络掩蔽或者IP掩蔽(IP masquerading)是一种IP数据包在通过路由器或防 ...

  5. NO---20 文件上传

    文件上传是我们会经常用到的一个业务,其实在h5中新增了FormData的对象,用它来提交表单,并且可以提交二进制文件,所以今天就写写文件上传,希望可以对大家有帮助 FormData 上传文件实例 首先 ...

  6. SVN For Mac: Cornerstone.app破解版免费下载

    Cornerstone.app下载地址 链接:https://pan.baidu.com/s/1kwQ65SBgfWXQur8Zdzkyyw  密码:rqe7 Cornerstone303 MAS.a ...

  7. 前端常见算法面试题之 - 从尾到头打印链表[JavaScript解法]

    题目描述 输入一个链表的头结点,从尾到头反过来打印出每个结点的值 实现思路 前端工程师看到这个题目,直接想到的就是,写个while循环来遍历链表,在循环中把节点的值存储在数组中,最后在把数组倒序后,遍 ...

  8. java后端面试题汇总

    转载链接:https://www.nowcoder.com/discuss/90776?type=0&order=0&pos=23&page=0 基础篇 数据结构与算法 线性表 ...

  9. resize2fs命令详解

    基础命令学习目录首页 原文链接:http://blog.51cto.com/woyaoxuelinux/1870299   resize2fs:调整ext文件系统的空间大小  搭配逻辑卷lv使用方法: ...

  10. [shell] 脚本之shift和getopts (转载)

    转载地址:http://www.361way.com/shell-shift-getopts/4973.html 建议不熟悉getopts的朋友,此篇要看完,getopts部分内容在原作者上面有改动. ...