Codeforces Round #471 (Div. 2) F. Heaps(dp)
题意
给定一棵以 \(1\) 号点为根的树。若满足以下条件,则认为节点 \(p\) 处有一个 \(k\) 叉高度为 \(m\) 的堆:
- 若 \(m = 1\) ,则 \(p\) 本身就是一个 \(k\) 叉高度为 \(1\) 的堆。
- 若 \(m > 1\) ,则 \(p\) 需要有至少 \(k\) 个儿子满足在儿子处有一个 \(k\) 叉高度为 \(m − 1\) 的堆。
令 \(dp[p][k]\) 表示在 \(p\) 点 \(k\) 叉堆的最大高度,令 \(g[p][k]\) 为 \(p\) 子树内最大的 \(dp[v][k]\) 求 \(\displaystyle \sum_{i=1}^{n} \sum_{j=1}^{n} g[i][j]\) 。
\(n \le 3 ∗ 10^5\)
题解
如果固定一个 \(k\) ,然后直接暴力做 \(dp\) ,每次是 \(O(n ^ 2)\) 的。
但显然是没必要这么暴力的,因为我们发现对于任意 \(k > 1\) ,都存在 \(dp[p][k] \le \log_{k} n\) 。
所以我们可以考虑做对于这个 \(dp\) 值的 \(dp\) ,具体来说令 \(f[p][x]\) 为满足 \(dp[p][k] \le x\) 的最大的 \(k\) 。
不难发现这样总状态是 \(O(n \log n)\) 的,接下来我们只需要考虑如何转移这个 \(dp\) 了。
考虑枚举一个点 \(p\) ,然后枚举它当前的层数 \(x \le 20\) ,然后考虑从它所有儿子的 \(x-1\) 的状态转移过来。
这个点的 \(f\) 取值显然不会超过儿子总数,然后考虑从大到小枚举 \(f\) 的取值 \(k\) 然后判断 \(f[v][x - 1]\) ( \(v\) 是 \(u\) 的一个儿子)中第 \(k\) 大的取值是否 \(\ge k\) ,如果可以则能取这个值。
这是因为它有 \(k\) 个儿子都满足至少具有 \(k\) 叉树的条件,那么这个点也能满足 \(k\) 叉树的条件。
然后最后记得要考虑 \(k=1\) 的情况(直接找向下最长链),然后答案就是 \(\sum_{i} (dep_i +\sum_{j} (f[i][j] - 1))\) 。
复杂度就是 \(O(n \log n ) \times O(\log n) = O(n \log^2 n)\) 的(因为有排序)。
总结
如果对于 \(dp\) 状态很多,但是取值很小的题,可以考虑对于 \(dp\) 值进行转移,常常状态就可以压到很少。
代码
其实很好写qwq
#include <bits/stdc++.h>
#define For(i, l, r) for(register int i = (l), i##end = (int)(r); i <= i##end; ++i)
#define Fordown(i, r, l) for(register int i = (r), i##end = (int)(l); i >= i##end; --i)
#define Set(a, v) memset(a, v, sizeof(a))
#define Cpy(a, b) memcpy(a, b, sizeof(a))
#define debug(x) cout << #x << ": " << (x) << endl
#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
#define pb push_back
using namespace std;
template<typename T> inline bool chkmin(T &a, T b) {return b < a ? a = b, 1 : 0;}
template<typename T> inline bool chkmax(T &a, T b) {return b > a ? a = b, 1 : 0;}
inline int read() {
int x(0), sgn(1); char ch(getchar());
for (; !isdigit(ch); ch = getchar()) if (ch == '-') sgn = -1;
for (; isdigit(ch); ch = getchar()) x = (x * 10) + (ch ^ 48);
return x * sgn;
}
void File() {
#ifdef zjp_shadow
freopen ("F.in", "r", stdin);
freopen ("F.out", "w", stdout);
#endif
}
const int N = 3e5 + 1e3, Lim = 20;
vector<int> G[N];
int n, f[N][Lim + 1], g[N], len;
void Dp(int u, int fa) {
for (int v : G[u]) if (v != fa) Dp(v, u);
f[u][1] = n;
For (i, 2, Lim) {
len = 0; for (int v : G[u]) if (v != fa) g[++ len] = f[v][i - 1];
sort(g + 1, g + len + 1, greater<int>());
Fordown (k, len, 1) if (g[k] >= k) { f[u][i] = k; break; }
}
}
int dep[N];
void Dfs(int u, int fa) {
dep[u] = 1;
for (int v : G[u]) if (v != fa) {
Dfs(v, u);
chkmax(dep[u], dep[v] + 1);
For (i, 1, Lim)
chkmax(f[u][i], f[v][i]);
}
}
long long ans = 0;
int main () {
File();
n = read();
For (i, 1, n - 1) {
int u = read(), v = read();
G[u].pb(v); G[v].pb(u);
}
Dp(1, 0); Dfs(1, 0);
For (i, 1, n) {
ans += dep[i];
For (j, 1, Lim)
if (f[i][j]) ans += f[i][j] - 1;
}
printf ("%lld\n", ans);
return 0;
}
Codeforces Round #471 (Div. 2) F. Heaps(dp)的更多相关文章
- Codeforces Round #260 (Div. 2)C. Boredom(dp)
C. Boredom time limit per test 1 second memory limit per test 256 megabytes input standard input out ...
- Codeforces Round #658 (Div. 2) D. Unmerge(dp)
题目链接:https://codeforces.com/contest/1382/problem/D 题意 给出一个大小为 $2n$ 的排列,判断能否找到两个长为 $n$ 的子序列,使得二者归并排序后 ...
- 【Codeforces】Codeforces Round #374 (Div. 2) -- C. Journey (DP)
C. Journey time limit per test3 seconds memory limit per test256 megabytes inputstandard input outpu ...
- Codeforces Round #652 (Div. 2) D. TediousLee(dp)
题目链接:https://codeforces.com/contest/1369/problem/D 题意 最初有一个结点,衍生规则如下: 如果结点 $u$ 没有子结点,添加 $1$ 个子结点 如果结 ...
- Codeforces Round #247 (Div. 2) C. k-Tree (dp)
题目链接 自己的dp, 不是很好,这道dp题是 完全自己做出来的,完全没看题解,还是有点进步,虽然这个dp题比较简单. 题意:一个k叉树, 每一个对应权值1-k, 问最后相加权值为n, 且最大值至少为 ...
- Codeforces Round #165 (Div. 1) Greenhouse Effect(DP)
Greenhouse Effect time limit per test 2 seconds memory limit per test 256 megabytes input standard i ...
- Codeforces Round #119 (Div. 2) Cut Ribbon(DP)
Cut Ribbon time limit per test 1 second memory limit per test 256 megabytes input standard input out ...
- Codeforces Round #368 (Div. 2) B. Bakery (模拟)
Bakery 题目链接: http://codeforces.com/contest/707/problem/B Description Masha wants to open her own bak ...
- Codeforces Round #587 (Div. 3) F. Wi-Fi(单调队列优化DP)
题目:https://codeforces.com/contest/1216/problem/F 题意:一排有n个位置,我要让所有点都能联网,我有两种方式联网,第一种,我直接让当前点联网,花费为i,第 ...
随机推荐
- pycharm导入自己写的.py文件时,模块下方出现红色波浪线解决
点击菜单栏的File,选择Setting, 然后,选择需要导入的.py文件“所在的目录",而非项目根目录,右键 之后再导入该.py文件就不会出现红色波浪线了.
- github导入文件操作
建立本地仓库: 创建新仓库的指令: git init //把这个目录变成Git可以管理的仓库 git add README.md //文件添加到仓库 git add . //不但可以跟单一文件,还可以 ...
- 如何使用 Docker 来限制 CPU、内存和 IO等资源?
如何使用 Docker 来限制 CPU.内存和 IO等资源?http://www.sohu.com/a/165506573_609513
- spring bean之间的关系:继承,依赖,注入
一 继承 spring中多个bean之间的继承关系,和面向对象中的继承关系类似,直接看代码. 先定义一个Person类 package com.demo.spring.entity; /** * @a ...
- 为什么js中要用void 0 代替undefined
这个是Backbone.js中的一句源码 if (callback !== void 0 && 'context' in opts && opts.context == ...
- Gevent 性能和 gevent.loop 的运用和带来的思考
知乎自己在底层造了非常多的轮子,而且也在服务器部署方面和数据获取方面广泛使用 gevent 来提高并发获取数据的能力.现在开始我将结合实际使用与测试慢慢完善自己对 gevent 更全面的使用和扫盲. ...
- Spring Boot 框架学习 (一)配置并运行Spring Boot 框架
下载开发工具: 下载完成打开以后,第一步检查环境 查看jdk是否配置: 接着一定要注意,maven通常情况下它是没有给你配置的,要自行配置: 右键新建: 然后依赖选择web.跟Mybatis就行了. ...
- 使用synchronized 实现ReentrantLock(美团面试题目)
刚看到这个题目的时候无从下手,因为觉得synchronized和lock在加锁的方式上有很大不同,比如,看看正常情况下synchronized时如何加锁的. 方式一: public synchroni ...
- python web需要了解哪些
1. socket.tcp/ip.http(cookie.session.token).https.ssl 2. wsgi:https://www.python.org/dev/peps/pep-33 ...
- oldriver
功能: 1:数据详情:统计商家所关联邮箱的商家店铺的当天或者最近一周,最近一个月的订单情况,sku,order,value,回评率数据在具体哪个国家的销售情况. 增强版提供更丰富的数据详情和自定义功能 ...