[CF791D]Bear and Tree Jumps
题目描述
A tree is an undirected connected graph without cycles. The distance between two vertices is the number of edges in a simple path between them.
Limak is a little polar bear. He lives in a tree that consists of n vertices, numbered 1 through n.
Limak recently learned how to jump. He can jump from a vertex to any vertex within distance at most k.
For a pair of vertices (s, t) we define f(s, t) as the minimum number of jumps Limak needs to get from s to t. Your task is to find the sum of f(s, t) over all pairs of vertices (s, t) such that s < t.
题目大意
算出各个节点之间距离和,答案是ans/k的向上取整。
40分解法
一股脑直接上一个\(dfs\),枚举每一个节点为根节点的情况,做\(n\)遍\(dfs\)。
40分代码
#include<bits/stdc++.h>
#define LL long long
#define inf
#define N 150005
using namespace std;
struct edge{int to,nt;}E[N<<1];
int H[N<<1],n,cas,k,cnt=0;
char s[1000];
LL ans=0;
int a,b,c,id;
int r(){int x=0,w=0;char ch=0;while(!isdigit(ch))w|=ch=='-',ch=getchar();while(isdigit(ch))x=(x<<1)+(x<<3)+(ch^48),ch=getchar();return w?-x:x;}
void addedge(int u,int v){E[++cnt]=(edge){v,H[u]};H[u]=cnt;E[++cnt]=(edge){u,H[v]};H[v]=cnt;}
void dfs(int u,int fa,int dis,int an){
for(int i=H[u];i;i=E[i].nt){
int v=E[i].to;if(v==fa)continue;
ans+=ceil((1.0*dis+1)/(1.0*k));
dfs(v,u,dis+1,an);
}
}
int main(){
cas=r(),n=r(),k=r();
for(int i=1;i<n;i++)addedge(r(),r());
for(int i=1;i<=n;i++)dfs(i,-1,0,i);
printf("%lld\n",ans/2);
return 0;
}
100分解法
我们思考一下,对于树上的一条边\(edge\),假设\(edge\)两边的点数分别是\(sum1\)和\(sum2\),那么我们可以知道通过这条边的路径一共有\(sum1*sum2\),乘法原理大家都明白。
那么我们就知道了全部的路径,但是这个是可以隔着跳的,那么我们就必须考虑有多出来的节点,也就是让当前距离+dist(我们计算多出来的距离)/k,才是我们的答案。
这样我们就把问题分成了两个部分,一个是算出\(ans\),也就是\(sum1\)和\(sum2\)乘机的和,还有一部分是\(sum\)表示的是需要我们将路径凑整的距离之和。
答案就变成了\((ans+sum)/k\)。
那么我们就考虑树上两点之间的距离是len=dep[u]+dep[v]-2dep[root],其中我们的root表示u节点和v节点的最近公共祖先,但是这道题的树形DP中,我们的v是属于u的儿子,那么这个距离不需要用LCA倍增做法来求,因为这个祖先就是u。
计算sum的方法:dp[i][j]表示到i点的距离对k取摸为j的点的总数。
转移我们需要枚举长度i,j(i和j都是mod的余下的距离)那么我们就要考虑这些点之间需要多跳的距离,首先算出这些点距离的余数是len=(i+j-2dep[u])%k,那么sum=(len-k)%k,因为我们要往大的跳,用乘法原理就是求出当前这个距离之间的点所有的点需要多跳的距离是lenf[u][a]f[v][b],这里非常好理解。
在说一下,我们在做这个树上dp的思路还是针对这个中间的edge。
下面说一下为什么在转移的时候为什么是直接f[u][a]+=f[v][a],这是因为我们基于通过(u,v)中间着一条边来处理,所以这个余数不需要考虑,也为已经考虑过了。
总的时间复杂度就是O(n*k^2),非常的优美。(一道树形dp的好题)
100分代码
#include<bits/stdc++.h>
#define N 200005
#define LL long long
using namespace std;
struct edge{int to,nt;}E[N<<1];
int cnt,n,k,H[N];
LL f[N][10],ans,sz[N];
int r(){int w=0,x=0;char ch=0;while(!isdigit(ch))w|=ch=='-',ch=getchar();while(isdigit(ch))x=(x<<1)+(x<<3)+(ch^48),ch=getchar();return w?-x:x;}
void addedge(int u,int v){E[++cnt]=(edge){v,H[u]};H[u]=cnt;E[++cnt]=(edge){u,H[v]};H[v]=cnt;}
void dfs(int u,int fa,int dep){
sz[u]=f[u][dep%k]=1;//计算到根节点的距离
for(int i=H[u];i;i=E[i].nt){//枚举所有相邻的边
int v=E[i].to; if(v==fa)continue;//是父亲就重来
dfs(v,u,dep+1);//向下递归算子树
for(int a=0;a<k;a++)//枚举第一个距离
for(int b=0;b<k;b++){//枚举第二个距离
int dis=(a+b-dep*2)%k;//求出距离
int rev=(k-dis)%k;//表示这里的每一个节点都需要多跳rev的距离
ans+=rev*f[u][a]*f[v][b];//运用乘法原理求出当前的sum
}
sz[u]+=sz[v];//将儿子v的大小赋值给u
for(int a=0;a<k;a++)f[u][a]+=f[v][a];//计算f数组。
ans+=sz[v]*(n-sz[v]);//算出当前的ans
}
}
int main(){
n=r(),k=r();
for(int i=1;i<n;i++)addedge(r(),r());
dfs(1,-1,0);printf("%lld\n",ans/k);
return 0;
}
[CF791D]Bear and Tree Jumps的更多相关文章
- Codefoces 791D. Bear and Tree Jumps 树形DP
D. Bear and Tree Jumps A tree is an undirected connected graph without cycles. The distance betwee ...
- 【树形dp】Codeforces Round #405 (rated, Div. 1, based on VK Cup 2017 Round 1) B. Bear and Tree Jumps
我们要统计的答案是sigma([L/K]),L为路径的长度,中括号表示上取整. [L/K]化简一下就是(L+f(L,K))/K,f(L,K)表示长度为L的路径要想达到K的整数倍,还要加上多少. 于是, ...
- CodeForces 771C Bear and Tree Jumps 树形DP
题意: 给出一棵树,一个人可以在树上跳,每次最多跳\(k(1 \leq k \leq 5)\)个点 定义\(f(s,t)\)为从顶点\(s\)跳到顶点\(t\)最少需要跳多少次 求\(\sum\lim ...
- 【codeforces 791D】 Bear and Tree Jumps
[题目链接]:http://codeforces.com/contest/791/problem/D [题意] 你可以从树上的节点一次最多走k条边. (称为跳一次); 树为无权树; 然后问你任意两点之 ...
- Codeforces 791D Bear and Tree Jump(树形DP)
题目链接 Bear and Tree Jumps 考虑树形DP.$c(i, j)$表示$i$最少加上多少后能被$j$整除. 在这里我们要算出所有$c(i, k)$的和. 其中$i$代表每个点对的距离, ...
- VK Cup 2017 - Round 1
和FallDream组队瞎打一通--B两个人写的都挂了233,最后只剩下FallDream写的A和我写的C,最后我yy了个E靠谱做法结果打挂了,结束之后改了改就A了,难受. AC:AC Rank:18 ...
- 【Codeforces Round #405 ( Div 2)】题解
Bear and Big Brother 签到题,直接模拟就可以了. Bear and Friendship Condition 满足只能是每个朋友圈中每个人和其他人都是朋友,这样的边数的确定的. 然 ...
- VK Cup 2017 - Round 1 (CDE)
771C Bear and Tree Jumps 大意: 给定树,每步能走到距离不超过$k$的任意点,记$f(s,t)$为$s$到$t$的最少步数,求$\sum\limits_{s<t}f(s, ...
- CF上部分树形DP练习题
本次 5 道题均来自Codeforce 关于树形DP的算法讲解:Here 791D. Bear and Tree Jumps 如果小熊每次能跳跃的距离为1,那么问题变为求树上任意两点之间距离之和. 对 ...
随机推荐
- HNOI2019 多边形 polygon
HNOI2019 多边形 polygon https://www.luogu.org/problemnew/show/P5288 这题镪啊... 首先堆结论: 显然终止状态一定是所有边都连向n了 根据 ...
- 从零开始搭建属于你的React/redux/webpack脚手架
大家好,我是苏南,今天要给大家分享的是<<我的react入门到放弃之路>>,当然,也不是真的放弃啦--哈哈,这篇博客原本是从17年初写的,一直没有在csdn发布,希望今天不会太 ...
- ASPCMS_判断语句if标签的使用
这几天在仿个企业站,又用到了ASPCMS.这个CMS系统支持响应式模板——视访问设备而使用不同的模板,这样PC.手机都能兼顾. ▼官方给出的说明: 1.满足条件则显示 {if:条件语句} 显示内容 { ...
- Pupet自动化管理环境部署记录
废话不多说了,下面记录下Puppet在Centos下的部署过程: puppet是什么puppet是一种基于ruby语言开发的Lnux.Unix.windows平台的集中配置管理系统.它使用自有的pup ...
- MySQL高可用方案-PXC环境部署记录
之前梳理了Mysql+Keepalived双主热备高可用操作记录,对于mysql高可用方案,经常用到的的主要有下面三种: 一.基于主从复制的高可用方案:双节点主从 + keepalived 一般来说, ...
- hdu 3038 给区间和,算出多少是错的
参考博客 How Many Answers Are Wrong Problem Description TT and FF are ... friends. Uh... very very good ...
- 《Linux内核分析》第七周: 可执行程序的装载
LINUX内核分析第七周学习总结--可执行程序的装载 杨舒雯(原创作品转载请注明出处) <Linux内核分析>MOOC课程http://mooc.study.163.com/course/ ...
- 纯MarkDown博客阅读体验优化
今天鼓捣了一天纯MarkDown书写的博客样式的美化,事实证明图表较多的MarkDown撰写的博文一样可以展现出非常漂亮的效果.为了让纯MarkDown书写的博客有一个干净舒服的阅读体验,我主要针对博 ...
- SpringMVC视图解析器概述
不论控制器返回一个String,ModelAndView,View都会转换为ModelAndView对象,由视图解析器解析视图,然后,进行页面的跳转. 控制器处理方法---->ModelAndV ...
- org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from class path resource [applicationContext.xml]; nested exception is java.io.FileNotFoundException: c
//这个是 配置文件放错了地方 org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing ...