首先最大独立集一定是很好求的把。。

题目中的是无根树,那么不妨转化成有根树,显然取重心作为根一般不会发生问题,因为这种情况下同构的子树形态完全相同;但是特殊情况是重心有2个的情况,如果直接取一个作为根的话会造成子树被破坏,解决方法是新建一个点作为根,向两个中心连边。

令f[x][0]表示不取x的本质不同的最大独立集的个数,f[x][1]表示取x的本质不用的最大独立集的个数。那么对于x的所有形态形同的子树,把它们的f[]放到一起转移。具体地:

设x的子树中某一形态的子树个数为t,且这种子树的f[][0]=a,f[][1]=b,考虑对f[x][0]的贡献(即累乘的值),对于每一个子树,一共有a+b种选择。那么如果不考虑本质不同,就有(a+b)^t种方案;如果要使得本质不同,我们不妨对a+b中选择进行编号1~a+b,然后给这t棵子树定一个顺序,强迫某一个子树选择的编号一定要大于等于前面一个子树选择的编号,显然这样的方案数就是本质不同的方案数。注意到这是一个相当经典的组合问题,只需要让第i棵子树选择的编号+i-1,那么就相当于在a+b+t-1个数中选择t个,也就是说贡献为C(a+b+t-1,t)。

判断子树是否相同,可以使用hash;或者给同一个深度的节点,相同编号的节点所在子树完全相同,那么对于深度-1的节点就很容易得到哪些节点相同了。hash方便快捷,但可能rp爆零;后面的(vfk称之为波兰式hash)比较麻烦,而且不如hash快,但是保证正确。。

hash用的素数一定要取得大一点。。。越大越好。不然很容易卡掉。另外hash函数可以设计得奇葩一点,并且要尽可能多的利用可用的信息。

AC代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 500005
#define ll long long
#define mod 1000000007
using namespace std;int n,tot=1,fst[N],pnt[N<<1],nxt[N<<1],sz[N],rt[2],inv[N],f[N][2],q[N];
ll hsh[N];
int read(){int x=0; char ch=getchar();while (ch<'0' || ch>'9') ch=getchar();while (ch>='0' && ch<='9'){ x=x*10+ch-'0'; ch=getchar(); }return x;
}
void add(int x,int y){pnt[++tot]=y; nxt[tot]=fst[x]; fst[x]=tot;
}
void dfs(int x,int fa){int p; bool ok=1; sz[x]=1;for (p=fst[x]; p; p=nxt[p]){int y=pnt[p];if (y!=fa){dfs(y,x); sz[x]+=sz[y];if ((sz[y]<<1)>n) ok=0;}}if ((sz[x]<<1)<n) ok=0;if (ok)if (rt[0]) rt[1]=x; else rt[0]=x;
}
bool cmp_hsh(int x,int y){ return hsh[x]<hsh[y]; }
int cbn(int x,int y){int tmp=x;for (; y>1; y--) tmp=(ll)tmp*(x-y+1)%mod*inv[y]%mod;return tmp;
}
void dp(int x,int fa){int p,i,j,tp=0;hsh[x]=20000909; for (p=fst[x]; p; p=nxt[p])if (pnt[p]!=fa) dp(pnt[p],x);for (p=fst[x]; p; p=nxt[p])if (pnt[p]!=fa) q[++tp]=pnt[p];sort(q+1,q+tp+1,cmp_hsh); f[x][0]=f[x][1]=1;for (i=1; i<=tp; i=j){for (j=i+1; j<=tp; j++) if (hsh[q[i]]!=hsh[q[j]]) break;f[x][0]=(ll)f[x][0]*cbn(((j-i-1+f[q[i]][0])%mod+f[q[i]][1])%mod,j-i)%mod;f[x][1]=(ll)f[x][1]*cbn((j-i-1+f[q[i]][0])%mod,j-i)%mod;}for (i=1; i<=tp; i++) hsh[x]=hsh[x]*2010527+(hsh[q[i]]+i)*1231231237;//这里的+i效果很显著
}
int main(){n=read(); int i,x,y;for (i=1; i<n; i++){x=read(); y=read();add(x,y); add(y,x);}inv[1]=1;for (i=2; i<=n; i++) inv[i]=mod-(ll)inv[mod%i]*(mod/i)%mod;dfs(1,0); int k;if (rt[1]){for (i=fst[rt[0]]; i; i=nxt[i]){y=pnt[i];if (y==rt[1]){ pnt[i]=pnt[i^1]=k=n+1; break; }}add(k,rt[0]); add(k,rt[1]);} else k=rt[0];dp(k,0);if (rt[1]){x=rt[0]; y=rt[1];if (hsh[x]!=hsh[y])printf("%d\n",((ll)f[x][0]*f[y][0]%mod+(ll)f[x][0]*f[y][1]%mod+(ll)f[x][1]*f[y][0]%mod)%mod);else printf("%d\n",((ll)f[x][0]*f[x][1]%mod+cbn(f[x][0]+1,2))%mod);}else printf("%d\n",(f[k][0]+f[k][1])%mod);return 0;
}

by lych

2016.4.7

bzoj 3162: 独钓寒江雪 树形dphash相关推荐

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

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

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

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

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

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

  4. bzoj 1369: Gem 树形dp

    题目大意 给出一棵树,要求你为树上的结点标上权值,权值可以是任意的正整数 唯一的限制条件是相临的两个结点不能标上相同的权值,要求一种方案,使得整棵树的总价值最小.N<=10000 题解 我们可以 ...

  5. BZOJ 4753 二分+树形DP

    思路: 先二分答案 f[x][j]表示在x的子树里选j个点 f[x][j+k]=max(f[x][j+k],f[x][j]+f[v[i]][k]); 初始化 x!=0 -> f[x][1]=p[ ...

  6. 洛谷4895 BZOJ3162 独钓寒江雪 树形dp 树哈希

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

  7. BZOJ 2651 城市改建 树形DP+模拟?

    题意 给一颗树,删除一条边再加一条边,使它仍为一颗树且任意两点间的距离的最大值最小. 题目数据范围描述有问题,n为1或重建不能使任意两点距离最大值变小,可以输出任意答案. 分析 删除一条边后会使它变成 ...

  8. 一句话题解(20170801~20170125)

    8.1 bzoj 4720 noip2016 换教室 floyd预处理+期望(薛定谔的猫) bzoj 4318 OSU! 三次函数期望值 从一次.二次推得 8.2 bzoj 1076 状压+期望DP ...

  9. BZOJ 2133 切割(树形DP,树上背包)大概是本题全网第一篇题解 >_<【BZOJ 修复工程】

    整理的算法模板合集: ACM模板 点我看算法全家桶系列!!! 实际上是一个全新的精炼模板整合计划 BZOJ 2133 切割这道题全网搜不到任何一篇题解 >_< 看评测记录也没有几个人AC- ...

  10. BZOJ.3227.[SDOI2008]红黑树tree(树形DP 思路)

    BZOJ orz MilkyWay天天做sxt! 首先可以树形DP:\(f[i][j][0/1]\)表示\(i\)个点的子树中,黑高度为\(j\),根节点为红/黑节点的最小红节点数(最大同理). 转移 ...

最新文章

  1. 华为手机怎样复制加密门禁卡_手机NFC复制小区用的门禁卡
  2. php透明颜色的代码,PHP 透明水印生成代码参考
  3. 学习笔记Kafka(三)—— Kafka安装配置(2)—— Kafka单代理及常用操作
  4. wp7 HubTile
  5. Struts2 控制台不打印异常的解决方案
  6. 新建maven(servlet项目) 引入不了HttpServlet
  7. EL表达式JSON应用
  8. python入门指南by许半仙-推文:拯救书荒(短篇小甜饼合集)
  9. 查看linux系统版本,内核,CPU,MEM,位数的相关命令
  10. vue cli3.0 解决跨域问题和axios等问题,配合Django
  11. iOS app 启动 crash XCode 11 NSPOSIXErrorDomain Code=2 “No such file or directory“
  12. ARP网关欺骗程序的实现(vs2008 winpacp)
  13. 西门子step7安装注册表删除_如何完全删除step 7
  14. 烟台蓬莱机场停车费一天多少钱,烟台机场停车哪里便宜
  15. android 罗盘陀螺仪,电子罗盘有什么用,安卓智能手机的感应器的问题! 电子罗盘与陀螺仪有......
  16. 论MongoDB索引选择的重要性
  17. UESTC 1636 梦后楼台高锁,酒醒帘幕低垂 最小生成树Kruskal算法的扩展
  18. SpringBoot实现163邮箱发送邮件
  19. 请假时间计算方式java_java计算两段时间的重复天数
  20. 单芯(多芯)液体不锈钢过滤器技术介绍

热门文章

  1. 使用mosquitto库命令与腾讯云通信
  2. 小程序AppID当前开发者未绑定此AppId,请到小程序管理后台操作后重试
  3. git报错warning: Clone succeeded, but checkout failed
  4. 如何在 Python 中使用 Plotly 创建太阳系的 3D 模型 (教程含源码)
  5. linux内核贡献排名,谷歌ARM靠边站!Linux内核贡献,华为反超Intel全球第一
  6. 容器技术—docker stack
  7. 微博研发实习阶段性总结及知识点整理
  8. php windows挂掉,宕机是什么意思
  9. 数据库中反引号的作用
  10. python建立ARIMA模型进行时间序列分析(氵论文)