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

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

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

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

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
int read()
{
int x=,f=;char c=getchar();
while (c<''||c>'') {if (c=='-') f=-;c=getchar();}
while (c>=''&&c<='') x=(x<<)+(x<<)+(c^),c=getchar();
return x*f;
}
#define N 500010
#define P 1000000007
#define ul unsigned long long
int n,p[N],p_new[N],f[N][],size[N],q[N],inv[N],root,t=;
ul hash[N];
struct data{int to,nxt;
}edge[N<<],edge_new[N<<];
void addedge(int x,int y){t++;edge[t].to=y,edge[t].nxt=p[x],p[x]=t;}
void addedge_new(int x,int y){t++;edge_new[t].to=y,edge_new[t].nxt=p_new[x],p_new[x]=t;}
void dfs(int k,int from)
{
size[k]=;
for (int i=p[k];i;i=edge[i].nxt)
if (edge[i].to!=from)
{
dfs(edge[i].to,k);
size[k]+=size[edge[i].to];
}
}
void dfs2(int k,int from)
{
for (int i=p[k];i;i=edge[i].nxt)
if (edge[i].to!=from)
{
addedge_new(k,edge[i].to);
dfs2(edge[i].to,k);
}
}
int findroot(int k,int from)
{
int mx=;
for (int i=p[k];i;i=edge[i].nxt)
if (edge[i].to!=from&&size[edge[i].to]>size[mx]) mx=edge[i].to;
if ((size[mx]<<)<=n) return k;
else return findroot(mx,k);
}
int C(int n,int m)
{
int ans=;
for (int i=n;i>=n-m+;i--) ans=1ll*ans*i%P;
return 1ll*ans*inv[m]%P;
}
bool cmp(const int&a,const int&b)
{
return hash[a]<hash[b];
}
void gethash(int k)
{
int cnt=;
for (int i=p[k];i;i=edge[i].nxt)
q[++cnt]=hash[edge[i].to];
sort(q+,q+cnt+);
for (int i=;i<=cnt;i++) hash[k]=hash[k]*+q[i];
hash[k]=(hash[k]*+size[k])%P;
}
void dp(int k)
{
for (int i=p[k];i;i=edge[i].nxt)
dp(edge[i].to),gethash(edge[i].to);
int cnt=;
for (int i=p[k];i;i=edge[i].nxt)
q[++cnt]=edge[i].to;
sort(q+,q+cnt+,cmp);
f[k][]=f[k][]=;
for (int i=;i<=cnt;i++)
{
int t=i;
while (t<cnt&&hash[q[t+]]==hash[q[i]]) t++;
f[k][]=1ll*f[k][]*C(f[q[i]][]+t-i,t-i+)%P;
f[k][]=1ll*f[k][]*C(f[q[i]][]+f[q[i]][]+t-i,t-i+)%P;
i=t;
}
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("bzoj3162.in","r",stdin);
freopen("bzoj3162.out","w",stdout);
const char LL[]="%I64d\n";
#else
const char LL[]="%lld\n";
#endif
n=read();
inv[]=inv[]=;for (int i=;i<=n;i++) inv[i]=P-1ll*(P/i)*inv[P%i]%P;
for (int i=;i<=n;i++) inv[i]=1ll*inv[i]*inv[i-]%P;
for (int i=;i<n;i++)
{
int x=read(),y=read();
addedge(x,y),addedge(y,x);
}
dfs(,);
root=findroot(,);
dfs(root,root);
int v=;
for (int i=p[root];i;i=edge[i].nxt)
if (!(n&)&&size[edge[i].to]==(n>>)) {v=edge[i].to;break;}
t=;
if (v)
{
n++;dfs2(root,v);dfs2(v,root);
addedge_new(n,root),addedge_new(n,v);root=n;
}
else dfs2(root,root);
memcpy(p,p_new,sizeof(p));
memcpy(edge,edge_new,sizeof(edge));
dfs(root,root);
dp(root);
if (v)
{
int x=edge[p[root]].to,y=edge[edge[p[root]].nxt].to;
if (hash[x]==hash[y])
f[root][]=(C(f[x][]+,)+1ll*f[x][]*f[x][]%P)%P;
else f[root][]=(1ll*f[x][]*(f[y][]+f[y][])%P+1ll*f[x][]*f[y][]%P)%P;
f[root][]=;
}
cout<<(f[root][]+f[root][])%P;
return ;
}

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的网站

    https://py.checkio.org/ 这个网站通过解决一些小任务引导初学者了解和使用python来处理一些实际需求.在coding的过程中还可以通过查看提示,帮助完成任务. 不过需要一点英文 ...

  2. Unity Shader 学习之旅

    Unity Shader 学习之旅 unityshader图形图像 纸上学来终觉浅,绝知此事要躬行 美丽的梦和美丽的诗一样 都是可遇而不可求的——席慕蓉 一.渲染流水线 示例图 Tips:什么是 GP ...

  3. PLSQL触发器,游标

    --触发器 drop table emp_log create table emp_log( empno number, log_date date, new_salary number, actio ...

  4. 学习python,第三篇:.pyc是个什么鬼?

    .pyc是个什么鬼? 1. Python是一门解释型语言? 我初学Python时,听到的关于Python的第一句话就是,Python是一门解释性语言,我就这样一直相信下去,直到发现了*.pyc文件的存 ...

  5. Hyperledger Fabric CA User’s Guide——概述(二)

    概述 下面的图表说明了如何将Hyperledger Fabric CA与总体的Hyperledger Fabric结构相匹配. 有两种方式与一种Hyperledger Fabric CA服务器进行交互 ...

  6. Openstack逻辑架构

    一. Keystone  -身份认证管理 提供了认证和授权的服务,openstack不同的组件通信都要经过授权,确保正确的用户和服务是经过认证的.并且它集成了大量的认证机制,比如用户名/密码和令牌/基 ...

  7. sqli-labs学习笔记 DAY7

    DAY7 sqli-labs阶段总结 基本步骤 判断是否报错 判断闭合符号 判断注入类型 构建payload 手工注入或者编写脚本 基本注入类型 报错型注入 floor公式(结果多出一个1):and ...

  8. 为什么找程序员一定要看他的 GitHub

    听说 最开始听到这句话是某知名互联网公司大牛告诉我的,我很不以为然,不过迫于他是"leader"我也注册了一个 highsea (广告 0.0):当然我可懒得 push 更别提 c ...

  9. js备忘录1

    新建对象 赋值和取值操作 var book={ topic:"JavaScript", fat: true }; book.topic  通过点访问 book["fat& ...

  10. LeetCode 655. Print Binary Tree (C++)

    题目: Print a binary tree in an m*n 2D string array following these rules: The row number m should be ...