题目链接: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. MySQL合理配置连接池数量

      我们经常会遇见“MySQL:ERROR1040:Toomanyconnections”的情况,一种是访问量确实很高,MySQL服务器抗不住,这个时候就要考虑增加从服务器分散读写压力,另外一种情况是 ...

  2. CSP-S初赛

    初赛都过了好几天了,现在才想起来写点关于初赛的博客也真是...... 我是福建人,是在福建的赛点参加的CSP-S组的初赛,能力其实很弱,估分只能60多一点点.真是害怕一不小心这篇博客就变成了我的退役博 ...

  3. Linux (x86) Exploit 开发系列教程之二(整数溢出)

    (1)漏洞代码 //vuln.c #include <stdio.h> #include <string.h> #include <stdlib.h> void s ...

  4. python--接口自动化测试(接口状态)

    本节开始,开始介绍python的接口自动化测试,首先需要搭建python开发环境,到https://www.python.org/下载python 版本直接安装就以了,建议 下载python2.7.1 ...

  5. golang之数组与切片

    数组 数组可以存放多个同一类型数据,数组也是一种数据类型,在Go中,数组是值类型. 数组的定义: var 数组名 [数组大小]数据类型 var a [5]int 赋初值   a[0] = 1    a ...

  6. 1,electron搭建

    electron可以用js来创建丰富的桌面应用 一个electron应用的目录结构 your-app/ ├── package.json ├── main.js └── index.html 1,安装 ...

  7. SAS学习笔记46 宏变量的可使用范围

    全局宏变量 在宏程序内部,除了使用%GLOBAL语句创建.在某些情况下,还可以直接使用DATA步中的CALL SYMPUT创建. 在一个宏程序中,在包含CALL SYMPUT的DATA步程序之前,如果 ...

  8. 第一个vue程序:hello,vlue

    <!DOCTYPE html> <html> <head> <meta charset="utf-8"> <meta http ...

  9. Sublime Text 开发神器相关 插件安装 功能介绍

    无法安装更多见http://blog.csdn.net/freshlover/article/details/44261229/ Sublime Text 3 安装插件管理 Package Contr ...

  10. [NOIP2018模拟赛10.23]发呆报告

    闲扯 考场看了眼题目感觉很难,一个小时敲完了所有暴力...嗯然后就在那里发呆什么事也没做 T3考场上把数据结构想了个遍都不会完成1操作,现在看这种思路其实之前也接触过... 比较玄学的一件事情就是T1 ...