题目链接:https://ac.nowcoder.com/acm/contest/884/G

题目大意:给定一个树\(A\),再给出\(t\)次询问,问\(A\)中有多少连通子图与树\(B_i\)同构。\(|A|\leq 2000,t\leq 10000, |B_i|\leq 12\)

题解:本题实际上是Codeforces 762F的加强版,关于这题的题解请戳这里

   本题做法与之前这道题类似,也是预处理出树的最小表示法后进行树形DP,但是由于这里有多达一万次询问,所以考虑预处理枚举所有点数不超过\(12\)的树并求出他们的最小表示。对于如何预处理所有满足条件的树,我的方法是假设当前树的大小为\(n\),将第\(n+1\)个点作为当前点或其祖先的儿子加入树中,并继续递归直至树的大小达到\(12\)。这样预处理后会发现点数不超过\(12\)的树只有不到\(8000\)个。接下来就是要对树\(A\)进行DP,设f[i][j]表示有多少以\(i\)为根节点的子树与编号为\(j\)的树同构,再令\(ans[j]=\sum_{i=1}^{n}f[i][j]\),对于每个询问的答案就是\(\sum ans[j]\),这里的\(j\)是树\(B\)以不同点为根时对应的编号。

   另外,在预处理的时候,我们同样可以预处理出当编号为\(j\)的树的根作为编号为\(i\)的树的根的儿子合并进来之后新树的编号,这样的合并关系只有不到\(14000\)组。这样对树\(A\)进行DP时就可以枚举所有这样的合并关系进行计算,将这一部分时间复杂度优化到\(O(14000n)\)

#include<bits/stdc++.h>
using namespace std;
#define N 2001
#define M 1<<12
#define MM 8001
#define NN 16773121
#define MOD 1000000007
int len(int x){return -__builtin_clz(x);}
int Union(int x,int y){return (x<<len(y))|y;}
int cnt;
set<int>id[];
int uni[MM][MM];
int num_to_id[NN];
int id_to_num[MM];
int f[N][MM];
vector<int>Id[];
struct Tree
{
int sz[N];
int n,ans[NN];
vector<int>d[N];
vector<int>mp[MM];
void read()
{
scanf("%d",&n);
for(int i=;i<=n;i++)
d[i].clear();
for(int i=;i<=n;i++)
{
int u,v;
scanf("%d%d",&u,&v);
d[u].push_back(v);
d[v].push_back(u);
}
}
int dfs(int cur,int pre)
{
sz[cur]=;
int res=;
vector<int>tmp;
for(auto nxt:d[cur])if(nxt!=pre)
tmp.push_back(dfs(nxt,cur)),sz[cur]+=sz[nxt];
sort(tmp.begin(),tmp.end());
for(auto x:tmp)res=Union(res,x);
res<<=;
if(!num_to_id[res])cnt++,mp[cnt]=tmp,id_to_num[cnt]=res,num_to_id[res]=cnt;
for(int i=;i<tmp.size();i++)
{
int R=;
for(int j=;j<tmp.size();j++)if(j!=i)
R=Union(R,tmp[j]);
R<<=;
uni[num_to_id[R]][num_to_id[tmp[i]]]=num_to_id[res];
}
id[sz[cur]].insert(num_to_id[res]);
return res;
}
void getID()
{
for(int i=;i<=n;i++)
dfs(i,);
}
void DP2(int cur,int pre)
{
sz[cur]=;
f[cur][]=;
for(auto nxt:d[cur])if(nxt!=pre)
{
DP2(nxt,cur);
for(int i=min(,sz[cur]);i>=;i--)
for(auto ii:Id[i])
{
int v=f[cur][ii];
if(!v)continue;
for(int j=;j<=min(-i,sz[nxt]);j++)
for(auto jj:Id[j])
(f[cur][uni[ii][jj]]+=v*f[nxt][jj]%MOD)%=MOD;
}
sz[cur]+=sz[nxt];
}
for(int i=;i<=min(,sz[cur]);i++)
for(auto ii:Id[i])
(ans[ii]+=f[cur][ii])%=MOD;
}
}S,T;
set<int>s;
int fa[];
vector<int>d[];
void fuck(int cur,int pre)
{
fa[cur]=pre;
for(int i=;i<=;i++)
T.d[i]=d[i];
T.n=cur;
if(cur==){T.dfs(,);return;}
int x=cur;
while(x!=)
{
d[x].push_back(cur+);
fuck(cur+,x);
d[x].pop_back();
x=fa[x];
}
}
int main()
{
fuck(,);
for(int i=;i<=;i++)
for(auto j:id[i])Id[i].push_back(j);
S.read();
S.DP2(,);
int t;
scanf("%d",&t);
while(t--)
{
T.read();
int ans=;
s.clear();
for(int i=;i<=T.n;i++)
s.insert(T.dfs(i,));
for(auto x:s)(ans+=S.ans[num_to_id[x]])%=MOD;
printf("%d\n",ans);
}
return ;
}

[2019牛客多校第四场][G. Tree]的更多相关文章

  1. 2019牛客多校第四场 I题 后缀自动机_后缀数组_求两个串de公共子串的种类数

    目录 求若干个串的公共子串个数相关变形题 对一个串建后缀自动机,另一个串在上面跑同时计数 广义后缀自动机 后缀数组 其他:POJ 3415 求两个串长度至少为k的公共子串数量 @(牛客多校第四场 I题 ...

  2. 2019牛客多校第四场 A meeting

    链接:https://ac.nowcoder.com/acm/contest/884/A来源:牛客网 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 524288K,其他语言10485 ...

  3. 牛客多校第四场 G Maximum Mode

    链接:https://www.nowcoder.com/acm/contest/142/G来源:牛客网 The mode of an integer sequence is the value tha ...

  4. 2019牛客多校第四场B xor——线段树&&线性基的交

    题意 给你 $n$ 个集合,每个集合中包含一些整数.我们说一个集合表示一个整数当且仅当存在一个子集其异或和等于这个整数.现在你需要回答 $m$ 次询问 ($l, r, x$),是否 $l$ 到 $r$ ...

  5. 2019牛客多校第四场J free——分层图&&最短路

    题意 一张无向图,每条边有权值,可以选择不超过 $k$ 条路使其权值变成0,求 $S$ 到 $T$ 的最短路.(同洛谷 P4568) 分析 首先,分层图最短路可以有效解决这种带有 「阶段性」的最短路, ...

  6. 2019牛客多校第四场A meeting——树的直径

    题意: 一颗 $n$ 个节点的树上标有 $k$ 个点,找一点使得到 $k$ 个关键结点的最大距离最小. 分析: 问题等价于求树的直径,最小距离即为直径除2向上取整. 有两种求法,一是动态规划,对于每个 ...

  7. 2019牛客多校第四场D-triples I 贪心

    D-triples 题意 给你一个\(n\),问至少有几个数或运算起来可以等于\(n\),并且输出数量和这个几个数.题目说明给的\(n\)一定符合条件(不会输出\(n= 1\) 之类不存在情况). 思 ...

  8. 2019牛客多校第四场C-sequence(单调栈+线段树)

    sequence 题目传送门 解题思路 用单调栈求出每个a[i]作为最小值的最大范围.对于每个a[i],我们都要乘以一个以a[i]为区间内最小值的对应的b的区间和s,如果a[i] > 0,则s要 ...

  9. 2019牛客多校第四场K number dp or 思维

    number 题意 给一个数字串,问有几个子串是300的倍数 分析 dp写法:这题一看就很dp,直接一个状态dp[i][j]在第i位的时候膜300的余数是j左过去即可.这题比赛的时候样例老是少1,后面 ...

随机推荐

  1. airflow删除dag不在页面显示

    当我们需要把dag删除的时候,遇到了删除了相应的dag文件,但页面还是显示 这个时候需要重启airflow 的webserver  ps -ef|egrep  rm -rf /home/airflow ...

  2. Docker部署Gitlab11.10.4

    1.下载镜像 官方镜像地址:https://hub.docker.com/r/gitlab/gitlab-ce ,根据自己需要下载指定版本 [root@vanje-dev01 ~]# docker p ...

  3. java日志框架系列(9):logback框架过滤器(filter)详解

    过滤器放在了logback-classic模块中. 1.logback-classic模块中过滤器 分类(2种):常规过滤器.TurboFilter过滤器. 1.常规过滤器 常规过滤器可以通过自定义进 ...

  4. WUSTOJ 1237: 将八进制的字符串转换成等价的十进制字符串(Java)

    1237: 将八进制的字符串转换成等价的十进制字符串 题目   输入八进制,输出十进制.更多内容点击标题. 分析   输入的八进制数有20位.已经超出了Integer.MAX_VALUE的范围,因此此 ...

  5. SQL Server 2017命令创建新账户(test-user),并分配数据库权限

    -- 1. 创建登录账号USE [master];GOCREATE LOGIN [test-user] WITH PASSWORD = 'xysu7SZ193SNX6E{{HxubPE3}vr',DE ...

  6. ASP.NET 使用 SyndicationFeed 输出 Rss

    以前生成 RSS 都是使用拼接 Xml 的方式生成的,不仅麻烦而且还不规范. #region 输出指定分类编号的消息源内容... /// <summary> /// 输出指定分类编号的消息 ...

  7. Docker启动Mongo报警告WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'.

    警告信息 2019-11-27T09:28:16.659+0000 I CONTROL [initandlisten] ** WARNING: /sys/kernel/mm/transparent_h ...

  8. ubuntu16下 Oracle安装完毕,测试是否安装成功的步骤

    1.查看oracle的环境变量,在终端输入命令 echo $ORACLE_BASE echo $ORACLE_HOME echo $PATH 看输出是不是安装时设置的路径 2.开启监听器 lsnrct ...

  9. session过期,登录页面嵌套问题解决

    项目主页是框架模式时,如果登录后长时间没有活动(操作),存储在session中的登录信息过期了,这时再去进行操作时,就会出现登录页面嵌套的问题,怎么解决呢? 这里介绍一种方法,只需要加上一段javas ...

  10. MyCAT详解【转】

    原文链接:MyCAT详解 作者:Rangle 一.MyCAT概述MyCAT是一款由阿里Cobar演变而来的用于支持数据库读写分离.分片的分布式中间件.MyCAT可不但支持Oracle.MSSQL.MY ...