题目链接: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. [转帖]Intel要提供2.5G的消费级以太网 价格2.4刀

    千兆网已成过去!Intel将全面普及2.5Gbps以太网 https://news.cnblogs.com/n/641736/ 硬件发展突飞猛进 投递人 itwriter 发布于 2019-10-02 ...

  2. JVM —— 类文件结构(下)

    简介 Java虚拟机的指令由一个字节长度的.代表着某种特定操作含义的操作码(opcode)以及跟随其后的零至多个代表此操作所需参数的操作数(operand)所构成 虚拟机中许多指令并不包含操作数.只有 ...

  3. (一)JMS简介

    一.简介 JMS即Java消息服务(Java Message Service)应用程序接口,是一个Java平台中关于面向消息中间件(MOM)的API,用于在两个应用程序之间,或分布式系统中发送消息,进 ...

  4. (八)shiro之jdbcRealm

    pom.xml <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w ...

  5. (四)自定义多个Realm以及Authenticator与AuthenticationStrategy

    多Realm配置 #声明一个realm myRealm1=com.github.zhangkaitao.shiro.chapter2.realm.MyRealm1 myRealm2=com.githu ...

  6. 使用隔离级别read committed隐式解决并发冲突

    1.使用rc的弊端:出现不可重复读 Oracle不可重复读 Oracle丢失修改 Oracle幻读 任何数据库的update  insert  delete都加排它锁 sql server的selec ...

  7. Deep Learning方向的paper

    转载 http://hi.baidu.com/chb_seaok/item/6307c0d0363170e73cc2cb65 个人阅读的Deep Learning方向的paper整理,分了几部分吧,但 ...

  8. Linux学习笔记:split切分文件并按规律命名及添加拓展名

    基础知识 功能:使用 shell 的 split 可以将一个大文件分割成很多个小文件,有时文件太大处理起来不方便就需要使用到了. 在默认情况下将按照每1000行切割成一个小文件. 语法: split ...

  9. windows的一些常用指令

    持续更新中..... 1.清除系统内 DNS 的缓冲  :  nslookup baidu.com 2.修改hosts文件  :  位置 运行  ->  C:/windows/system32/ ...

  10. OpenStack kilo版(1) 部署环境

    硬件 VMware workstation虚拟机 Ubuntu14.04操作系统 虚拟机网络规划 管理网络: eth0, 桥接模式 10.0.0.0/24 外部网络: eth1, nat模式(需要关闭 ...