题目链接: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的BashOperator中执行docker容器中的脚本容易忽略的问题

    dag模板 from airflow import DAG from airflow.operators.bash_operator import BashOperator from airflow. ...

  2. 登陆Linux服务器时触发邮件提醒

    目前,客户只能在发现数据或者虚拟机被恶意侵入或者用户的误操作导致了数据的丢失之后,采取善后的手段,但是并没法做到提前的预警.那么通过 PAM 模块,就可以实现用户登录及获取root 权限时,通过邮件的 ...

  3. [转帖]YES!AMD千元无敌U闪亮登场、16核至尊为用户着想

    YES!AMD千元无敌U闪亮登场.16核至尊为用户着想 投递人 itwriter 发布于 2019-09-30 09:34 评论(0) 有567人阅读 原文链接 [收藏] « » https://ne ...

  4. Oracle的varchar2如何比较大小

    首先要说的是Oracle中字符类型的比较都是基于ASCII码表来实现的,我就简单做个总结. Oracle中varchar2类型的字符串使用的是非填充空格的标准来进行比较的(表格中右边的那列,注意空格的 ...

  5. nohup启动后台进程并重定向

    一:linux重定向 0,1,2分别表示标准输入,标准输出和标准错误输出,一般情况下默认是标准输出 a. 1>log:标准输出重定向的log文件 b. 2>log:错误输出重定向到log文 ...

  6. aliplay获取播放时长

    <div id="player-con" class="frequency-pic"></div> <link rel=" ...

  7. mini.DataGrid使用说明

    mini.DataGrid表格.实现分页加载.自定义列.单元格渲染.行编辑器.锁定列.过滤行.汇总行等功能.Extend    mini.PanelUsage <div id="dat ...

  8. Java代理模式示例程序

    Java代理模式示例程序 当然不是我想出来的,是我看的一个网上教程里的. 模拟的是一个对电脑公司的代理 真实类的接口: public interface SaleComputer { public S ...

  9. Recastnavigation 创建 off-mesh link 的潜规则

    Recastnavigation 在创建off-mesh link 时,发现有的off-mesh link 无法寻路(虽然在地图上能看到off-mesh link 的连线   在Google Grou ...

  10. AngularJS入门教程之与服务器(Ajax)交互操作示例

    AngularJS从Web服务器请求资源都是通过Ajax来完成,所有的操作封装在$http服务中,$http服务是只能接收一个参数的函数,这个参数是一个对象,用来完成HTTP请求的一些配置,函数返回一 ...