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

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

代码:

  1. #include<cstdio>
  2. #include<algorithm>
  3. #include<vector>
  4. #include<map>
  5. using namespace std;
  6. inline int read()
  7. {
  8. int x;char c;
  9. while((c=getchar())<''||c>'');
  10. for(x=c-'';(c=getchar())>=''&&c<='';)x=x*+c-'';
  11. return x;
  12. }
  13. #define MN 1000
  14. #define MM 13
  15. #define MOD 1000000007
  16. struct edge{int nx,t;}e[MN*+MM*+];
  17. int h[MN+],H1[MM+],H2[MM+],en;
  18. int m,s[MM+],rts,rtx,rty,t[MM+],cnt;
  19. vector<int> v[MM+],vv[MM+];
  20. map<long long,int> mp;
  21. int f[MN+][MN+][MM+];
  22. inline void ins(int*h,int x,int y)
  23. {
  24. e[++en]=(edge){h[x],y};h[x]=en;
  25. e[++en]=(edge){h[y],x};h[y]=en;
  26. }
  27. void dfs(int x,int fa)
  28. {
  29. s[x]=;
  30. int mx=;
  31. for(int i=H1[x];i;i=e[i].nx)if(e[i].t!=fa)
  32. {
  33. dfs(e[i].t,x);
  34. s[x]+=s[e[i].t];
  35. mx=max(mx,s[e[i].t]);
  36. }
  37. mx=max(mx,m-s[x]);
  38. if(mx<rts)rts=mx,rtx=x,rty=;
  39. else if(mx==rts)rty=x;
  40. }
  41. void solve(int x,int fa)
  42. {
  43. long long hash=;
  44. for(int i=H2[x];i;i=e[i].nx)if(e[i].t!=fa)
  45. {
  46. solve(e[i].t,x);
  47. vv[x].push_back(t[e[i].t]);
  48. }
  49. sort(vv[x].begin(),vv[x].end());
  50. for(int i=;i<vv[x].size();++i)hash=hash*+vv[x][i];
  51. t[x]=mp[hash]?mp[hash]:(v[++cnt]=vv[x],mp[hash]=cnt);
  52. }
  53. inline void rw(int&a,int b){if((a+=b)>=MOD)a-=MOD;}
  54. int cal(int x,int fa,int t)
  55. {
  56. if(f[x][fa][t])return f[x][fa][t]-;
  57. int *F=new int[<<v[t].size()];
  58. for(int i=F[]=;i<<<v[t].size();++i)F[i]=;
  59. for(int i=h[x];i;i=e[i].nx)if(e[i].t!=fa)
  60. for(int j=<<v[t].size();j--;)
  61. for(int k=;k<v[t].size();++k)
  62. if(!(j&(<<k))&&(!k||(j&(<<k-))||v[t][k]!=v[t][k-]))
  63. rw(F[j|(<<k)],1LL*F[j]*cal(e[i].t,x,v[t][k]));
  64. f[x][fa][t]=F[(<<v[t].size())-]+;delete F;
  65. return f[x][fa][t]-;
  66. }
  67. int main()
  68. {
  69. int n,i,j,ans=;
  70. for(n=read(),i=;i<n;++i)ins(h,read(),read());
  71. for(m=read(),i=;i<m;++i)ins(H1,read(),read());
  72. rts=m;dfs(,);
  73. if(rty)
  74. {
  75. if(rtx>rty)swap(rtx,rty);
  76. for(i=;i<=m;++i)for(j=H1[i];j;j=e[j].nx)
  77. if(i<e[j].t&&(i!=rtx||e[j].t!=rty))ins(H2,i,e[j].t);
  78. ins(H2,rtx,++m);ins(H2,rty,m);rtx=m;
  79. }
  80. 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);
  81. solve(rtx,);
  82. if(rty)for(i=;i<=n;++i)for(j=h[i];j;j=e[j].nx)if(i<e[j].t)
  83. {
  84. rw(ans,1LL*cal(i,e[j].t,v[t[m]][])*cal(e[j].t,i,v[t[m]][])%MOD);
  85. if(v[t[m]][]!=v[t[m]][])
  86. rw(ans,1LL*cal(i,e[j].t,v[t[m]][])*cal(e[j].t,i,v[t[m]][])%MOD);
  87. }else;
  88. else for(i=;i<=n;++i)rw(ans,cal(i,,t[rtx]));
  89. printf("%d",ans);
  90. }

[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. Alpha冲刺Day5

    Alpha冲刺Day5 一:站立式会议 今日安排: 首先由于经过黄腾飞短暂的测试,发现导入导出仍然有一些问题,今天需要进行完善 由黄腾飞负责企业自查风险管理子模块,要求为单元进行风险点的管理 由张梨贤 ...

  2. 项目Beta冲刺Day1

    项目进展 李明皇 今天解决的进度 点击首页list相应条目将信息传到详情页 明天安排 优化信息详情页布局 林翔 今天解决的进度 前后端连接成功 明天安排 开始微信前端+数据库写入 孙敏铭 今天解决的进 ...

  3. python利用twilio模块给自己发短信

    1.访问http://twilio.com/并填写注册表单.注册了新账户后,你需要验证一个手机号码,短信将发给该号码. 2.Twilio 提供的试用账户包括一个电话号码,它将作为短信的发送者.你将需要 ...

  4. 微信支付 chooseWXPay:fail

    本来以为解决了微信支付get_brand_wcpay_request:faill这个问题后就万事大吉了,结果又迈入了另一个坑... 问题原因: 1.生成签名的时间戳参数名timestamp的s大小写问 ...

  5. EXT3文件系统误删除导致文件系统中的邮件丢失恢复方法

    一.故障描述 由8块盘组成的RAID5, 上层是EXT3文件系统,由于误删除导致文件系统中的邮件丢失 二.镜像磁盘为防止数据恢复过程中由于误操作对原始磁盘造成二次破坏, 使用winhex软件为每块磁盘 ...

  6. 通过URL传递PDF名称参数显示PDF

    1 <%@ page language="java" import="java.util.*,java.io.*" 2 pageEncoding=&quo ...

  7. signalR 消息推送

    业务情景一:上传报表,上传excel.如果excel的数据量很大,上万条,上十万条数据,那么这个上传请求必然是个耗时请求.用户上传之后,很关心上传的进度和结果. 业务情景二:站内消息提醒,实时有效地接 ...

  8. EasyUI内容页Tabs。

    html: <div data-options="region:'center'"> <div id="tabs" class="e ...

  9. (转载) Mysql 时间操作(当天,昨天,7天,30天,半年,全年,季度)

    1 . 查看当天日期 select current_date(); 2. 查看当天时间 select current_time(); 3.查看当天时间日期 select current_timesta ...

  10. kubernetes入门(09)kubernetes1.7集群安装(2017/11/13)

    CentOS7.3利用kubeadm安装kubernetes1.7.3完整版(官方文档填坑篇) https://www.cnblogs.com/liangDream/p/7358847.html 一. ...