[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,那么问题变为求树上任意两点之间距离之和. 对 ...
随机推荐
- Android开发——ListView使用技巧总结(二)
0. 前言 Android中的ListView是用的比较多的控件之一,在上一篇Android开发--ListView使用技巧总结(一)中对ListView的ViewHolder机制.优化卡顿方式以及 ...
- 2011 noip 提高组
首先吐槽:刚刚写着写着突然蓝屏了,,emmm,写到最后一题了蓝屏了. 当时我的内心是崩溃的. 然后,旁边的大佬默默来了一句:论保存草稿的重要性. 连着蓝了三次之后开了防火墙,然后,,我左边那位同学又开 ...
- 面试2——java基础2
11.MVC设计模型 mvc设计模型是一种使用model-view-controller(模型-视图-控制器)设计创建web应用程序的模式.是一种开发模式,好处是可以将界面和业务逻辑分离. model ...
- python爬虫xpath的语法
有朋友问我正则,,okey,其实我的正则也不好,但是python下xpath是相对较简单的 简单了解一下xpath: XPath 是一门在 XML 文档中查找信息的语言.XPath 可用来在 XML ...
- HTTP请求头和响应头部包括的信息有哪些?
每个HTTP请求和响应都会带有相应的头部信息.默认情况下,在发送XHR请求的同时,还会发送下列头部信息: Accept:浏览器能够处理的内容类型 Accept-Charset:浏览器能够显示的字符集 ...
- "一个程序员的生命周期"读后感
这篇文章中作者叙述了自己和大多数大学生或许都会面对的问题,即是会走过挺多的歪路,面临很多的困难和压力,但是作者却从未放弃自己真正追求的东西.对于一个过来人的经验之谈,我们应该吸取经验,在大学好好去奋斗 ...
- HDU 2096 小明A+B
http://acm.hdu.edu.cn/showproblem.php?pid=2096 Problem Description 小明今年3岁了, 现在他已经能够认识100以内的非负整数, 并且能 ...
- Fixed the bug:while running alert/confirm in javascript the chrome freezes
显示高级设置... 系统 -> 使用硬件加速模式(如果可用) 操作系统如果不支持硬件加速,却启动此项,就悲催了.小伙伴们可别瞎点了,太吃亏. 现象alert/confirm一执行,chrome ...
- Qt__绘制系统
Qt绘制系统简介 Qt 的绘图系统允许使用相同的 API 在屏幕和其它打印设备上进行绘制.整个绘图系统基于QPainter,QPainterDevice和QPaintEngine三个类. QPaint ...
- 第八周PSP 新折线图和饼图 个人时间管理
1.PSP DATE START-TIME END-TIME EVENT DELTA TYPE 4.18 15.36 16.10 读构建执法 走神5min 29mi ...