719D(树形dp)
题目链接:http://codeforces.com/contest/791/problem/D
题意:给出一棵树,每两个点之间的距离为1,一步最多可以走距离 k,问要将任意两个点之间的路径都走一遍,最少需要走多少步;
思路:对于不是很简单的问题我们可以将问题分解成若干步或许会简单一点,对于本题我们可以先考虑只求所有路径的距离之和, 假设我们求得其值为ans;不过因为有些路径的长度并不是m的整倍数,所以我们不能直接用ans/m得到答案;不过如果我们能找到所有不是m的整倍数的路径并且可以求出其%m的值的话,那么我们可以给其补上一个尽量小的数并使其能整除m, 那么我们只要将所有补加的数累加到ans里面去,那么ans/m就是我们要的答案啦。。。
接下来我们需要考虑一下具体如何实现上面两步:
对于如何求得ans,我们可以计算出对于每条边经过他的路径数,就是这条边对ans的贡献值,那么累加对于每条边经过她的路径数就是ans啦;每条边都是由相邻的两个节点构成的,我们可以将两个节点看做父子节点,那么经过这条边的路径的数目为son*(n-son),其中son为子节点所在的子树的大小,那么n-son就是子树外的节点数目(这个应该挺好理解的,不理解的画下图就明白了);显然我们只要dfs搜一遍就能得到ans啦;
下面我们只要求出长度%m不为整数的路径就ok了。我们不防这样想,从某点出发的所有路径中任选两条可以组成一条经过该点的路径,那么所有组合即为所有经过该点的路径。
我们用dp[i][j]记录从点 i 出发%m为 j 的路径的数目,那么我们可以同过 j 的组合得到经过点 i 长度%m=j'的路径数目,显然只要求出dp[i][j]我们很容易得到补加的的值是多少。
若对于当前节点i, 我们已知dp[i][j],那么显然对于其父节点有 dp[i'][(j+1)] = dp[i][j],所以我们我们可以在dfs回溯时通过dp计算出dp[i][j]的值;对叶子节点初始化为dp[i][0]=1;
至此已经圆满解决这个问题啦。。
代码:
#include <iostream>
#include <stdio.h>
#include <vector>
#define ll long long
using namespace std; const int MAXN=2e5+;
int n, m;
bool vis[MAXN];//标记当前节点是否搜过
vector<int> mp[MAXN];
ll dp[MAXN][], son[MAXN], ans=;//dp[i][j]存储以i为根节点,i的子树中距离i长度mod k==j的的路径的条数,son[i]记录i的子树大小 void dfs(int point){
son[point]=;//相当于将两个数组初始化为 1
dp[point][]=;
for(int i=; i<mp[point].size(); i++){
int v=mp[point][i];
if(!vis[v]){
vis[v]=true;
dfs(v);
son[point]+=son[v];//将子树中节点的数目加到当前节点上
ans+=(son[v])*(ll)(n-son[v]);//统计经过边[point,i]的路径数目
for(int j=; j<m; j++){
for(int k=; k<m; k++){
if((j+k+)%m){
ans+=dp[point][j]*dp[v][k]*(ll)(m-(j+k+)%m);//i+j+k为分别由点point,及一个其子节点引出的路径长度%m再求和
}
}
}
for(int j=; j<m; j++){
dp[point][(j+)%m]+=dp[v][j];//从节点mp[point][i]回溯到其父节点,那么由原来mp[point][i]的子树到其的距离%m=j的路径数目转移得到point的子树到其距离+1%m=j的路径数目
}
}
}
} int main(void){
scanf("%d%d", &n, &m);
for(int i=; i<n; i++){
int x, y;
scanf("%d%d", &x, &y);
mp[x].push_back(y);
mp[y].push_back(x);
}
vis[]=true;
dfs();
printf("%lld\n", ans/m);
return ;
}
719D(树形dp)的更多相关文章
- poj3417 LCA + 树形dp
Network Time Limit: 2000MS Memory Limit: 65536K Total Submissions: 4478 Accepted: 1292 Descripti ...
- COGS 2532. [HZOI 2016]树之美 树形dp
可以发现这道题的数据范围有些奇怪,为毛n辣么大,而k只有10 我们从树形dp的角度来考虑这个问题. 如果我们设f[x][k]表示与x距离为k的点的数量,那么我们可以O(1)回答一个询问 可是这样的话d ...
- 【BZOJ-4726】Sabota? 树形DP
4726: [POI2017]Sabota? Time Limit: 20 Sec Memory Limit: 128 MBSec Special JudgeSubmit: 128 Solved ...
- 树形DP+DFS序+树状数组 HDOJ 5293 Tree chain problem(树链问题)
题目链接 题意: 有n个点的一棵树.其中树上有m条已知的链,每条链有一个权值.从中选出任意个不相交的链使得链的权值和最大. 思路: 树形DP.设dp[i]表示i的子树下的最优权值和,sum[i]表示不 ...
- 树形DP
切题ing!!!!! HDU 2196 Anniversary party 经典树形DP,以前写的太搓了,终于学会简单写法了.... #include <iostream> #inclu ...
- BZOJ 2286 消耗战 (虚树+树形DP)
给出一个n节点的无向树,每条边都有一个边权,给出m个询问,每个询问询问ki个点,问切掉一些边后使得这些顶点无法与顶点1连接.最少的边权和是多少.(n<=250000,sigma(ki)<= ...
- POJ2342 树形dp
原题:http://poj.org/problem?id=2342 树形dp入门题. 我们让dp[i][0]表示第i个人不去,dp[i][1]表示第i个人去 ,根据题意我们可以很容易的得到如下递推公式 ...
- hdu1561 The more, The Better (树形dp+背包)
题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=1561 思路:树形dp+01背包 //看注释可以懂 用vector建树更简单. 代码: #i ...
- bzoj2500: 幸福的道路(树形dp+单调队列)
好题.. 先找出每个节点的树上最长路 由树形DP完成 节点x,设其最长路的子节点为y 对于y的最长路,有向上和向下两种情况: down:y向子节点的最长路g[y][0] up:x的次长路的g[x][1 ...
随机推荐
- ABAP 调用webservice 错误
错误:1.soamanager 配置端口错误: 调整端口后报错: java端回复: 嗯 有问题了我待会儿看看应该是数据有问题
- ABAP 关键字(1)
1.定义DATA ,TYPES TYPES关键字用于创建自定义数据类型,就像JAVA里面创建类一样,用TYPES创建的数据类型可以被其它变量引用(类似于实例化对象),而本身不能直接引用或者赋值. DA ...
- git 从远端拉取指定分支和推送本地某个分支到远端
如题,可以直接从远端拉取某个分支,也可以直接将本地某个分支推送到远端. 原文链接:https://www.cnblogs.com/hamsterPP/p/6810831.html
- 微信小程序开发:学习笔记[1]——Hello World
微信小程序开发:学习笔记[1]——Hello World 快速开始 1.前往微信公众平台下载微信开发者工具. 地址:https://mp.weixin.qq.com/debug/wxadoc/dev/ ...
- make和rest用法
位置(position):下一个要读取或写入的数据的索引.缓冲区的位置不能为负,并且不能大于其限制(limit). 标记(mark)与重置(reset):标记是一个索引,通过Buffer中的mark( ...
- Buffer的数据存取
缓冲区 存放要读取的数据 缓冲区 和 通道 配合使用 一个用于特定基本数据类行的容器.有java.nio包定义的,所有缓冲区都是抽象类Buffer的子类. Java NIO中的Buffer主要用于与N ...
- pycharm解决Inconsistent indentation:mix of tabs and spaces
- Eclipse_插件_03_反编译插件_Eclipse Class Decompiler
一.插件优势 此插件比jd-eclipse更加强大,反编译之后不会像jd-eclipse一样出现注释符号. 二.插件下载地址 1.github https://github.com/cnfree/Ec ...
- Linux(Ubuntu16.04)+GitLab8.17deb安装包搭建Git仓库(代码管理系统)
1 下载GitLab安装包 2 执行安装命令 3 验证是否安装和启动成功 4 修改管理员密码 5 其它说明 5.1修改访问URL 5.2修改邮件配置 5.3修改web端口 1下载GitLab安装包 ...
- 转 对APK进行重签名
1. 生成Android APK包签名证书1). 在doc中切换到jdk的bin目录cd C:\Program Files\Java\jdk1.6.0_18\bin2). 运 ...