FJOI2014 树的重心

\(Q\) 组测试数据。给一棵树大小为 \(n\),求有多少个子树与其重心相同。重心可能有多个。

数据范围:\(1\le Q\le 50\),\(1\le n\le 200\)。


就是要写好几个 \(\tt dp\) 吧,细节比较多。


先 \(\tt Dfs\) 一次找个重心:

int sz[N+7],g[N+7];
int Dfs1(int u,int fa){
int res=inf;
sz[u]=1,g[u]=0;
for(int&v:e[u])if(v!=fa){
res=min(res,Dfs1(v,u));
sz[u]+=sz[v],g[u]=max(g[u],sz[v]);
}
g[u]=max(g[u],n-sz[u]);
res=min(res,g[u]);
return res;
}
//...
int ms=Dfs1(1,0);
vector<int> G;
for(int i=1;i<=n;i++)if(g[i]==ms) G.pb(i);

重心只有 \(1\) 个或 \(2\) 个,于是分类讨论 。


  • 有 \(2\) 个重心

设重心为 \(Gx\) 和 \(Gy\)。

所以必然有边 \((Gx,Gy)\)。

把 \((Gx,Gy)\) 断开后两部分子树必然是相等的(要不然就只有 \(1\) 个重心)。

所以可以在两部分子树以 \(Gx,Gy\) 为根各写个 \(\tt dp\):

\(f_{u,i}\) 表示 \(u\) 点的子树选 \(i\) 个点的联通子树(包括 \(u\) 点)的方案数。

\[f_{u,i}=\sum_{v\in son_u}\sum_{j=1}^{\min(i-1,sz_v)}f_{u,i-j}\cdot f_{v,j}
\]

然后 \(Ans=\sum_{i=1}^{\min(sz_{Gx},sz_{Gy})}f_{Gx,i}\cdot f_{Gy,i}\)。

不过写两次树形 \(\tt dp\) 麻烦,我的代码中省了个树形 \(\tt dp\)。


  • 有 \(1\) 个重心

设重心为 \(G\)。

所以选出子树中 \(G\) 点的每个子树大小 \(\le\) 所有子树大小之和的 \(\frac 12\)。

所以可以先如上跑个 \(\tt dp\),以 \(G\) 为根得出同上的 \(f_{i,j}\)。

\(F_{i,j}\) 选出子树共 \(i\) 个点(除了 \(G\)),最大子树大小为 \(j\) 的方案数。

所以初始化 \(F_{i,i}=\sum_{v\in son_G}f_{v,i}\)。

\[{\rm Then}\forall k\in[1,i]:F_{i,\max(j,k)}+=F_{i-j,k}\cdot f_{v,j}
\]

最后 \(Ans=1+\sum_{i=1}^n\sum_{j=1}^n[2j\le i]F_{i,j}\)。

为什么要 \(+1\)?表示只选 \(G\) 点的情况。


  • 代码
#include <bits/stdc++.h>
using namespace std; //Start
typedef long long ll;
typedef double db;
#define mp(a,b) make_pair(a,b)
#define x first
#define y second
#define b(a) a.begin()
#define e(a) a.end()
#define sz(a) int((a).size())
#define pb(a) push_back(a)
const int inf=0x3f3f3f3f;
const ll INF=0x3f3f3f3f3f3f3f3f; //Data
const int N=200,P=1e4+7;
int n;
vector<int> e[N+7]; //Treedp
int sz[N+7],g[N+7],f[N+7][N+7];
int Dfs1(int u,int fa){
int res=inf;
sz[u]=1,g[u]=0;
for(int&v:e[u])if(v!=fa){
res=min(res,Dfs1(v,u));
sz[u]+=sz[v],g[u]=max(g[u],sz[v]);
}
g[u]=max(g[u],n-sz[u]);
res=min(res,g[u]);
return res;
}
void Dfs2(int u,int fa){
sz[u]=f[u][0]=f[u][1]=1;
for(int&v:e[u])if(v!=fa){
Dfs2(v,u),sz[u]+=sz[v];
for(int i=sz[u];i>=1;i--)
for(int j=1;j<=min(sz[v],i-1);j++)
(f[u][i]+=f[u][i-j]*f[v][j]%P)%=P;
}
} //KonnyWen
int F1[N+7][N+7],F2[N+7];
int KonnyWen(){
scanf("%d",&n);
for(int i=1;i<=n;i++) e[i].clear();
for(int i=1,u,v;i<=n-1;i++){
scanf("%d%d",&u,&v);
e[u].pb(v),e[v].pb(u);
}
int ms=Dfs1(1,0);
vector<int> G;
for(int i=1;i<=n;i++)if(g[i]==ms) G.pb(i);
// puts("G:");
// for(int&x:G) printf("%d ",x);puts("");
memset(f,0,sizeof f),Dfs2(G[0],0);
// puts("f:");
// for(int i=1;i<=n;i++)
// for(int j=1;j<=n;j++)
// printf("%d%c",f[i][j],"\n "[j<n]);
int sm=0,res=0;
if(sz(G)==1){
memset(F1,0,sizeof F1),ms=-inf;
for(int&v:e[G[0]]){
ms=max(ms,sz[v]),sm+=sz[v];
for(int i=sm;i>=1;i--)
for(int j=min(sz[v],i);j>=1;j--){
if(j==i) (F1[i][j]+=f[v][j])%=P;
else for(int k=1;k<=min(i,ms);k++)
(F1[i][max(j,k)]+=F1[i-j][k]*f[v][j]%P)%=P;
}
}
// puts("F1:");
// for(int i=1;i<=n;i++)
// for(int j=1;j<=n;j++)
// printf("%d%c",F1[i][j],"\n "[j<n]);
for(int i=1;i<=sm;i++)
for(int j=1;j<=i;j++)
if(j*2<=i) (res+=F1[i][j])%=P;
res++;
} else if(sz(G)==2){ //一次树形 dp 代替两次
memset(F2,0,sizeof F2),F2[0]=1;
for(int&v:e[G[0]])if(v!=G[1]){
sm+=sz[v];
for(int i=sm;i>=1;i--)
for(int j=1;j<=min(sz[v],i);j++)
(F2[i]+=F2[i-j]*f[v][j]%P)%=P;
}
// puts("F2:");
// for(int i=1;i<=n;i++) printf("%d ",F2[i]);puts("");
for(int i=1;i<=sm+1;i++)
(res+=F2[i-1]*f[G[1]][i]%P)%=P;
}
return res;
} //Main
int main(){
int t; scanf("%d",&t);
for(int i=1;i<=t;i++)
printf("Case %d: %d\n",i,KonnyWen());
return 0;
}

祝大家学习愉快!

题解-FJOI2014 树的重心的更多相关文章

  1. [题解] LuoguP5666 树的重心

    这个题......确实是CSPNOIP题qwq 感觉猜到一个性质就差不多了,首先,对于一棵树,随便拎一个节点\(rt\)当根节点,那么他的重心一定在\(rt\)的重儿子里,进一步的,可以发现重心一定在 ...

  2. POJ 1655 Balancing Act ( 树的重心板子题,链式前向星建图)

    题意: 给你一个由n个节点n-1条边构成的一棵树,你需要输出树的重心是那个节点,以及重心删除后得到的最大子树的节点个数size,如果size相同就选取编号最小的 题解: 树的重心定义:找到一个点,其所 ...

  3. CSP2019 树的重心 题解

    本题当然可以通过大力讨论每棵子树的size的大小关系,然后用各种数据结构暴力维护.但是我更倾向于用一种更为性质的做法. 首先讲一下我在考场上想到的做法(没写).就是考虑换根,在换根的过程中计算每一条边 ...

  4. [CSP-S2019]树的重心 题解

    CSP-S2 2019 D2T3 考场上扔了T2来打这题的部分分,然后没看到数据范围是等号,不知道怎么判完全二叉树然后40分滚粗…… ---- 思路分析 很容易想到$O(n^2)$每次暴力找重心,这个 ...

  5. POJ 1655 求树的重心

    POJ 1655 [题目链接]POJ 1655 [题目类型]求树的重心 &题意: 定义平衡数为去掉一个点其最大子树的结点个数,求给定树的最小平衡数和对应要删的点.其实就是求树的重心,找到一个点 ...

  6. 洛谷P3345 [ZJOI2015]幻想乡战略游戏(动态点分治,树的重心,二分查找,Tarjan-LCA,树上差分)

    洛谷题目传送门 动态点分治小白,光是因为思路不清晰就耗费了不知道多少时间去gang这题,所以还是来理理思路吧. 一个树\(T\)里面\(\sum\limits_{v\in T} D_vdist(u,v ...

  7. 点分治模板(洛谷P4178 Tree)(树分治,树的重心,容斥原理)

    推荐YCB的总结 推荐你谷ysn等巨佬的详细题解 大致流程-- dfs求出当前树的重心 对当前树内经过重心的路径统计答案(一条路径由两条由重心到其它点的子路径合并而成) 容斥减去不合法情况(两条子路径 ...

  8. POJ 1655 - Balancing Act - [DFS][树的重心]

    链接:http://poj.org/problem?id=1655 Time Limit: 1000MS Memory Limit: 65536K Description Consider a tre ...

  9. BZOJ 3510 - 首都 「 $LCT$ 动态维护树的重心」

    这题 FlashHu 的优化思路值得借鉴 前置引理 树中所有点到某个点的距离和中,到重心的距离和是最小的. 把两棵树通过某一点相连得到一颗新的树,新的树的重心必然在连接原来两棵树重心的路径上. 一棵树 ...

随机推荐

  1. linux用户的增删改查(useradd/id/usermod/userdel)

    与用户(user)相关的配置文件:  /etc/passwd 注:用户(user)的配置文件: /etc/shadow 注:用户(user)影子口令文件: 与用户组(group)相关的配置文件:  / ...

  2. appium-appium的等待时间

    #三种appium设置等待时间的方法 #第一种 sleep(): 设置固定休眠时间. python 的 time 包提供了休眠方法 sleep() , 导入 time包后就可以使用 sleep()进行 ...

  3. python的pip快速安装代码

    pip install xx,经常由于网速,或者安装版本问题导致安装速度慢超时等问题, 现提供一个py镜像安装代码,安装库文件前执行下这个程序,可以很快下载 cmd 进入命令提示符 python .p ...

  4. Apache Shiro 1.2.4反序列化漏洞(CVE-2016-4437)复现

    Apache Shiro 1.2.4反序列化漏洞(CVE-2016-4437)复现 环境搭建 docker pull medicean/vulapps:s_shiro_1 docker run -d ...

  5. day94:flask:Jinjia2模板引擎&flask中的CSRF攻击&Flask-SQLAlchemy的创建模型类和基本的增删改查

    目录 1.Jinjia2模板引擎 1.Jinjia2加载模板并传递数据到模板中 2.Jinjia2的模板语句 3.模板中特有的变量和函数 4.模板中内置的过滤器 5.自定义过滤器 6.模板继承 2.在 ...

  6. 厉害!这份阿里面试官 甩出的Spring源码笔记,GitHub上已经爆火

    前言 时至今日,Spring 在 Java 生态系统与就业市场上,面试出镜率之高,投产规模之广,无出其右.随着技术的发展,Spring 从往日的 IoC 框架,已发展成 Cloud Native 基础 ...

  7. Guitar Pro小课堂之弹唱和弦转换小技巧

    吉他相对其他乐器的便携性,还有其便于弹唱的特点,受到了很多音乐萌新们的喜爱.对于刚刚接触吉他的萌新来说,学琴初期弹唱的时候经常会因为和弦卡顿的转换,和因为食指力度不够或技巧不对无法顺利演奏的大横按,导 ...

  8. 如何使用会声会影制作动态logo字幕

    日常生活中大家在参加一些婚礼.聚会的时候,LED屏幕上播放的视频里面常常会有一行字,它随着视频的播放自己也在不断地改变颜色,非常醒目.想必大家也想把这种动态文字用在自己的视频中,为视频增添亮点.那么今 ...

  9. 思维导图MindManager流程图有哪些功能

    流程图是思维导图中的一种图表,应用相当广泛.MindManager 2020作为专业的思维导图软件,更加强了流程图的功能,让用户能使用更加简便的MindManager技巧绘制流程图.接下来,就让我们一 ...

  10. 「CERC2017」Donut Drone

    题目链接 洛谷P4739 题目翻译: 你正在模拟无人机探索一个不稳定的环状行星的过程.技术上说,无人机正在穿过一个环形网格---一个在两维上都首尾环绕在一起的矩形网格.格子的行号从上到下依次编号为\( ...