[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,那么问题变为求树上任意两点之间距离之和. 对 ...
随机推荐
- tensorflow笔记:多层LSTM代码分析
tensorflow笔记:多层LSTM代码分析 标签(空格分隔): tensorflow笔记 tensorflow笔记系列: (一) tensorflow笔记:流程,概念和简单代码注释 (二) ten ...
- CRC---循环冗余校验
typedef unsigned char uchar; typedef unsigned int uint; typedef unsigned short uInt16; uint crc; // ...
- flask_admin 笔记七 扩展功能
高级功能 1,开启CSRF保护 要将CSRF保护添加到由ModelView实例生成的表单中,请通过指定form_base_class参数在ModelView子类中使用SecureForm类: from ...
- 【下一代核心技术DevOps】:(四)私有镜像库阿里云Docker服务使用
1.使用阿里云镜像库有很多优点 稳定可靠,阿里技术,放心使用. 国内cdn多节点加速,下载速度非常快 可以和阿里云Git代码集成,不需要第三方CI工具,当然带的自动构建服务也可以和其他的Git库集成, ...
- Centos下SFTP双机高可用环境部署记录
SFTP(SSH File Transfer Protocol),安全文件传送协议.有时也被称作 Secure File Transfer Protocol 或 SFTP.它和SCP的区别是它允许用户 ...
- rsync同步时,删除目标目录比源目录多余文件的方法(--delete)
在日常运维工作中,我们经常用到rsync这个同步神器.有时在同步两个目录时,会要求删除目标目录中比源目录多出的文件,这种情况下,就可用到rsync的--delete参数来实现这个需求了. 实例说明:在 ...
- Linux实践三:程序破解
一.汇编指令机器码 二.反汇编与十六进制编程器 三.可执行文件的基本格式 hexdump -x login 用16进制数字显示login内容 objdump -x login 显示login中各个段以 ...
- Oracle的安装与配置
好久不来博客园了,有种熟悉而又陌生的感觉. 今天我装一下Oracle数据库,从头开始,因为昨天在虚拟机装了,不能用,卸掉了,系统也卸掉了,今天重新装,包括系统. 系统装好了,Oracle准备好了. 这 ...
- 201306114357-实验3-C语言
#include<stdio.h>#include <stdlib.h>#include <time.h>main(){ int a,b,c,n,u,i,sum; ...
- HDOJ2025_查找最大元素
一道简单题 HDOJ2025_查找最大元素 #include<stdio.h> #include<stdlib.h> #include<ctype.h> #incl ...