题目大意:给出一棵n个点的树和一棵m个点的树,问第一棵树有多少个连通子树与第二棵树同构。(n<=1000,m<=12)

做法:先找出第二棵树的重心(可能为边),以这个重心为根,可以避免重复计算,顺便对第二棵树的每个子树算出判同构的哈希值。枚举第一棵树的一个点/边与第二棵树的根对应,用f[i][j][k]表示以j为父亲的i的子树内,选出子树哈希值为k的方案数,合并的时候用状压DP。前两维合在一起是O(n)级别的,所以总复杂度是O(nm*2^m)。

代码:

#include<cstdio>
#include<algorithm>
#include<vector>
#include<map>
using namespace std;
inline int read()
{
int x;char c;
while((c=getchar())<''||c>'');
for(x=c-'';(c=getchar())>=''&&c<='';)x=x*+c-'';
return x;
}
#define MN 1000
#define MM 13
#define MOD 1000000007
struct edge{int nx,t;}e[MN*+MM*+];
int h[MN+],H1[MM+],H2[MM+],en;
int m,s[MM+],rts,rtx,rty,t[MM+],cnt;
vector<int> v[MM+],vv[MM+];
map<long long,int> mp;
int f[MN+][MN+][MM+];
inline void ins(int*h,int x,int y)
{
e[++en]=(edge){h[x],y};h[x]=en;
e[++en]=(edge){h[y],x};h[y]=en;
}
void dfs(int x,int fa)
{
s[x]=;
int mx=;
for(int i=H1[x];i;i=e[i].nx)if(e[i].t!=fa)
{
dfs(e[i].t,x);
s[x]+=s[e[i].t];
mx=max(mx,s[e[i].t]);
}
mx=max(mx,m-s[x]);
if(mx<rts)rts=mx,rtx=x,rty=;
else if(mx==rts)rty=x;
}
void solve(int x,int fa)
{
long long hash=;
for(int i=H2[x];i;i=e[i].nx)if(e[i].t!=fa)
{
solve(e[i].t,x);
vv[x].push_back(t[e[i].t]);
}
sort(vv[x].begin(),vv[x].end());
for(int i=;i<vv[x].size();++i)hash=hash*+vv[x][i];
t[x]=mp[hash]?mp[hash]:(v[++cnt]=vv[x],mp[hash]=cnt);
}
inline void rw(int&a,int b){if((a+=b)>=MOD)a-=MOD;}
int cal(int x,int fa,int t)
{
if(f[x][fa][t])return f[x][fa][t]-;
int *F=new int[<<v[t].size()];
for(int i=F[]=;i<<<v[t].size();++i)F[i]=;
for(int i=h[x];i;i=e[i].nx)if(e[i].t!=fa)
for(int j=<<v[t].size();j--;)
for(int k=;k<v[t].size();++k)
if(!(j&(<<k))&&(!k||(j&(<<k-))||v[t][k]!=v[t][k-]))
rw(F[j|(<<k)],1LL*F[j]*cal(e[i].t,x,v[t][k]));
f[x][fa][t]=F[(<<v[t].size())-]+;delete F;
return f[x][fa][t]-;
}
int main()
{
int n,i,j,ans=;
for(n=read(),i=;i<n;++i)ins(h,read(),read());
for(m=read(),i=;i<m;++i)ins(H1,read(),read());
rts=m;dfs(,);
if(rty)
{
if(rtx>rty)swap(rtx,rty);
for(i=;i<=m;++i)for(j=H1[i];j;j=e[j].nx)
if(i<e[j].t&&(i!=rtx||e[j].t!=rty))ins(H2,i,e[j].t);
ins(H2,rtx,++m);ins(H2,rty,m);rtx=m;
}
else for(i=;i<=m;++i)for(j=H1[i];j;j=e[j].nx)if(i<e[j].t)ins(H2,i,e[j].t);
solve(rtx,);
if(rty)for(i=;i<=n;++i)for(j=h[i];j;j=e[j].nx)if(i<e[j].t)
{
rw(ans,1LL*cal(i,e[j].t,v[t[m]][])*cal(e[j].t,i,v[t[m]][])%MOD);
if(v[t[m]][]!=v[t[m]][])
rw(ans,1LL*cal(i,e[j].t,v[t[m]][])*cal(e[j].t,i,v[t[m]][])%MOD);
}else;
else for(i=;i<=n;++i)rw(ans,cal(i,,t[rtx]));
printf("%d",ans);
}

[Codeforces]762F - Tree nesting的更多相关文章

  1. [Educational Round 17][Codeforces 762F. Tree nesting]

    题目连接:678F - Lena and Queries 题目大意:给出两个树\(S,T\),问\(S\)中有多少连通子图与\(T\)同构.\(|S|\leq 1000,|T|\leq 12\) 题解 ...

  2. 『Tree nesting 树形状压dp 最小表示法』

    Tree nesting (CF762F) Description 有两个树 S.T,问 S 中有多少个互不相同的连通子图与 T 同构.由于答案 可能会很大,请输出答案模 1000000007 后的值 ...

  3. Educational Codeforces Round 17F Tree nesting

    来自FallDream的博客,未经允许,请勿转载, 谢谢. 给你两棵树,一棵比较大(n<=1000),一棵比较小(m<=12) 问第一棵树中有多少个连通子树和第二棵同构. 答案取膜1e9+ ...

  4. Codeforces 675D Tree Construction Splay伸展树

    链接:https://codeforces.com/problemset/problem/675/D 题意: 给一个二叉搜索树,一开始为空,不断插入数字,每次插入之后,询问他的父亲节点的权值 题解: ...

  5. Codeforces 570D TREE REQUESTS dfs序+树状数组 异或

    http://codeforces.com/problemset/problem/570/D Tree Requests time limit per test 2 seconds memory li ...

  6. Codeforces 570D - Tree Requests【树形转线性,前缀和】

    http://codeforces.com/contest/570/problem/D 给一棵有根树(50w个点)(指定根是1号节点),每个点上有一个小写字母,然后有最多50w个询问,每个询问给出x和 ...

  7. Codeforces 23E Tree

    http://codeforces.com/problemset/problem/23/E 题意:给一个树,求砍断某些边,使得所有联通块大小的乘积最大.思路:f[i][j]代表当前把j个贡献给i的父亲 ...

  8. Codeforces 1092F Tree with Maximum Cost(树形DP)

    题目链接:Tree with Maximum Cost 题意:给定一棵树,树上每个顶点都有属性值ai,树的边权为1,求$\sum\limits_{i = 1}^{n} dist(i, v) \cdot ...

  9. Codeforces 911F Tree Destruction

    Tree Destruction 先把直径扣出来, 然后每个点都和直径的其中一端组合, 这样可以保证是最优的. #include<bits/stdc++.h> #define LL lon ...

随机推荐

  1. 高级软件工程2017第6次作业--团队项目:Alpha阶段综合报告

    高级软件工程2017第6次作业--团队项目:Alpha阶段综合报告 Deadline:2017-10-30(周一)21:00pm (注:以下内容参考集大作业4,集大作业5,集大作业6,集大作业7 一. ...

  2. 每日冲刺报告——Day1(Java-Team)

    第一天报告(11.2  周四) 团队:Java-Team 成员: 章辉宇(284) 吴政楠(286) 陈阳(PM:288) 韩华颂(142) 胡志权(143) github地址:https://git ...

  3. C语言的第0次作业

    你认为大学的学习生活.同学关系.师生关系应该是怎样? 1.我觉得大学生活应该充实而富有意义,不荒废学业,合理分配时间,让自己有一技之长,与时代接轨. 2.同学之间应该顺其自然的相处,不做作,不矫情,真 ...

  4. 201621123062《java程序设计》第三周作业总结

    1.本周学习总结 初学面向对象,会学习到很多碎片化的概念与知识.尝试学会使用 将这些碎片化的概念.知识点组织起来.请使用工具画出本周学习到的知识点及知识点之间的联系.步骤如下: 1.1写出你认为本周学 ...

  5. 如何减小ios安装包大小

    以前的老文章了,搬到cnblog 更小的安装包意味着更快的下载安装速度,也往往意味着更快的加载运行速度,是优化ios应用的一个重要方面,本文主要参考<减小iOS应用程序的大小>,在实际测试 ...

  6. DML数据操作语言之查询(一)

    1.select语句基础 基本语句格式:  select <列名>,.... from <表名>; select子句中列举出希望从表中查询出的列的名称,from子句则指定了选取 ...

  7. 逆向集录_00_不同程序OEP特征总结

    在分析/逆向 程序时,如果事先知道这类程序的一些特征,那将会是事半功倍的: 分析/逆向 程序,和写程序不同,比喻的话:写程序像在作案,分析/逆向 程序就像是在破案,对破案来讲,重在假想和推理: 特征1 ...

  8. KNN算法的代码实现

    # -*- coding: utf-8 -*-"""Created on Wed Mar 7 09:17:17 2018 @author: admin"&quo ...

  9. jquery 实时监听输入框值变化方法

    $('.offers-number').bind('input propertychange', function (a, b) { var value = $(this).val() if (!va ...

  10. 新概念英语(1-121)The man in a hat

    Why didn't Caroline recognize the customer straight away ?A:I bought two expensive dictionaries here ...