「COCI2016/2017 Contest #2」Bruza

解题思路 :

首先对于任意时刻 \(i\) ,硬币一定移动到了深度为 \(i\) 的节点,所以第 \(i\) 时刻 Danel 一定染掉一个深度为 \(i + 1\) 的节点。又因为如果硬币到了深度为 \(k\) 的节点游戏就结束了,所以深度 \(> k\) 的节点都可以忽视,把所有深度 \(= k\) 的节点看做这棵树的叶子,如果一个节点其子树里面没有深度 \(= k\) 的节点,那么这整棵子树也是可以被忽视的。

其次,如果染色的一个节点是另外一个节点的祖先,那么深度较深的那个节点被染是没有意义的。

那么每次染掉一个深度为 \(i\) 的节点,其至少会使得 \(k-i+1\) 个节点无法到达,那么染 \(k\) 次能染掉的节点数量的下界就是:

\[\sum_{i=1}^k k - i + 1= k(k+1)-\frac{k(k+1)}{2}=\frac{k(k+1)}{2}
\]

于是可以得到一个关于 \(k\) 的较松的上界,当满足时 Danel 必胜:

\[k \geq \sqrt{2n}
\]

实际上这个上界是比较松的,可以继续证明并加以利用。观察发现如果染掉一个没有分叉的节点,等价于染掉其子树中第一个有分叉的节点。那么可以除了根节点以外,每次染掉深度最小的一个有分叉的节点,且要保证任意时刻 \(i\) ,染掉的深度 \(\leq i\) 的节点个数必须 $\leq i $ 。

显然,如果每种深度的节点有分叉的仅有一个,那么Danel必胜。

假设在某一时刻出现两个深度最小为 \(d\) 且有分叉的节点,那么其中一个有分叉的节点不能被染掉。相当于转化为进入这个节点所对应的子树的一个子问题,而在这之前,通过染色使得不能到达的最少节点数量之和是:

\[\sum_{i=1}^d 2k - i =2kd-\frac{d(d+1)}{2}
\]

解释一下这个式子,假设之前的被染色的每一个节点都只有两个分叉,且这两个分叉对应的子树都是以两条链的形式存在的,这样显然是最少的情况,此时被减少至不能到达的部分就是该节点到根的路径以及这两个分叉。

令 \(S(n, k)\) 为初始状态的规模,此时进入的子问题的规模是 \(S(n', k')\) ,根据上述分析一下可以得到:

\[k' = k - d \\
n' = n - 2kd+\frac{d(d+1)}{2} \\
n' \leq n - 2kd + d^2
\]

在这里假设一个更小的上界使得当满足时 Danel 必胜:

\[k \geq \sqrt{n} \\
k^2 \geq n
\]

那么之前的式子

\[k' = k - d \\
n' \leq k^2 - 2kd + d^2 \\
n' \leq (k -d)^2
\]

此时 \(S(n',k')\) 仍然满足假设的上界 \(k \geq \sqrt{n}\) ,这里归纳证明得到了一个更小的上界当满足时 Danel 必胜。

把问题带回最初的贪心思路,第 \(i\) 次选择深度为 \(i+1\) 的节点一定是最优的,那么深度 \([2,k]\) 每种只能染最多一个节点,且最终要使得所有叶子都有一个祖先在染色的点集里面。

把问题转化到反dfn序上,令 \(dp(i, s)\) 表示反dfn序前 \(i\) 为已经选了深度集合为 \(s\) 的点能覆盖的最多叶子数量,为了防止对叶子的贡献重复计数,同一子树内不能同时选,那么转移的时候讨论一下就好了

\[dp(i, s) =\max(dp(i-1,s), dp(i-sz[i],s-2^{dep[i]})+val[i])
\]

其中 \(sz[i]\) 是反dfn序上第 \(i\) 位对应的节点的大小,\(val[i]\) 是这个节点的子树中的叶子节点数量,最后看一下是否存在一个 \(dp\) 状态能覆盖所有叶子即可,总复杂度 \(O(n2^\sqrt{n})\)。

据说还有 \(O(\sqrt{n}2^{\sqrt{n}})\) 的做法, 又据说一言难尽,改天再填坑吧。

code

/*program by mangoyang*/
#pragma GCC optimize("Ofast","inline","-ffast-math")
#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<bits/stdc++.h>
#define inf (0x7f7f7f7f)
#define Max(a, b) ((a) > (b) ? (a) : (b))
#define Min(a, b) ((a) < (b) ? (a) : (b))
typedef long long ll;
using namespace std;
template <class T>
inline void read(T &x){
int ch = 0, f = 0; x = 0;
for(; !isdigit(ch); ch = getchar()) if(ch == '-') f = 1;
for(; isdigit(ch); ch = getchar()) x = x * 10 + ch - 48;
if(f) x = -x;
} const int N = 405; vector<int> g[N];
int f[N][(1<<17)+2], vi[N][(1<<17)+2];
int sz[N], d[N], dfn[N], mx[N], h[N], leaf, n, k, cnt, all, tot; inline int MX(int x, int y){ return x > y ? x : y; } inline int solve(int u, int s){
if(~f[u][s]) return f[u][s];
if(s == all || u > cnt) return f[u][s] = 0;
if(u == 1 || (1 << d[u]) & s || mx[u] < k) return f[u][s] = solve(u + 1, s);
return f[u][s] = MX(solve(u + sz[u], s | (1 << d[u])) + h[u], solve(u + 1, s));
}
inline void dfs(int u, int fa){
dfn[u] = ++cnt; sz[dfn[u]] = 1;
if(u > 1) d[dfn[u]] = d[dfn[fa]] + 1;
mx[dfn[u]] = d[dfn[u]];
if(d[dfn[u]] == k) return (void) (leaf++, h[dfn[u]] = 1);
for(int i = 0; i < g[u].size(); i++){
int v = g[u][i];
if(v == fa) continue;
dfs(v, u), sz[dfn[u]] += sz[dfn[v]], h[dfn[u]] += h[dfn[v]];
mx[dfn[u]] = MX(mx[dfn[u]], mx[dfn[v]]);
}
}
int main(){
memset(f, -1, sizeof(f));
read(n), read(k), all = (1 << k) - 1;
if(k * k >= n) return puts("DA"), 0;
for(int i = 1, x, y; i < n; i++){
read(x), read(y);
g[x].push_back(y), g[y].push_back(x);
}
dfs(1, 0);
for(int i = 1; i <= n; i++) d[i]--;
puts(solve(1, 0) >= leaf ? "DA" : "NE");
return 0;
}

「COCI2016/2017 Contest #2」Bruza的更多相关文章

  1. loj #6250. 「CodePlus 2017 11 月赛」找爸爸

    #6250. 「CodePlus 2017 11 月赛」找爸爸 题目描述 小 A 最近一直在找自己的爸爸,用什么办法呢,就是 DNA 比对. 小 A 有一套自己的 DNA 序列比较方法,其最终目标是最 ...

  2. [LOJ#6259]「CodePlus 2017 12 月赛」白金元首与独舞

    [LOJ#6259]「CodePlus 2017 12 月赛」白金元首与独舞 试题描述 到河北省 见斯大林 / 在月光下 你的背影 / 让我们一起跳舞吧 うそだよ~ 河北省怎么可能有 Stalin. ...

  3. [LOJ 6249]「CodePlus 2017 11 月赛」汀博尔

    Description 有 n 棵树,初始时每棵树的高度为 H_i,第 i 棵树每月都会长高 A_i.现在有个木料长度总量为 S 的订单,客户要求每块木料的长度不能小于 L,而且木料必须是整棵树(即不 ...

  4. [LOJ 6248]「CodePlus 2017 11 月赛」晨跑

    Description “无体育,不清华”.“每天锻炼一小时,健康工作五十年,幸福生活一辈子” 在清华,体育运动绝对是同学们生活中不可或缺的一部分.为了响应学校的号召,模范好学生王队长决定坚持晨跑.不 ...

  5. 「JOISC 2017 Day 3」幽深府邸

    题解: 和hnoi2018day2t1基本一样 我想了半小时想出了一个很麻烦的做法 写了之后发现假掉了 刚开始想的是 先预处理出每个门要打开至少要在左边的哪个点$L[]$,右边的哪个点$R[]$ 对每 ...

  6. 「CodePlus 2017 11 月赛」Yazid 的新生舞会(树状数组/线段树)

    学习了新姿势..(一直看不懂大爷的代码卡了好久T T 首先数字范围那么小可以考虑枚举众数来计算答案,设当前枚举到$x$,$s_i$为前$i$个数中$x$的出现次数,则满足$2*s_r-r > 2 ...

  7. 「CodePlus 2017 11 月赛」大吉大利,晚上吃鸡!(dij+bitset)

    从S出发跑dij,从T出发跑dij,顺便最短路计数. 令$F(x)$为$S$到$T$最短路经过$x$的方案数,显然这个是可以用$S$到$x$的方案数乘$T$到$x$的方案数来得到. 然后第一个条件就变 ...

  8. 「CodePlus 2017 12 月赛」火锅盛宴(模拟+树状数组)

    1A,拿来练手的好题 用一个优先队列按煮熟时间从小到大排序,被煮熟了就弹出来. 用n个vector维护每种食物的煮熟时间,显然是有序的. 用树状数组维护每种煮熟食物的数量. 每次操作前把优先队列里煮熟 ...

  9. 「CodePlus 2017 12 月赛」可做题2(矩阵快速幂+exgcd+二分)

    昨天这题死活调不出来结果是一个地方没取模,凉凉. 首先有个一眼就能看出来的规律... 斐波那契数列满足$a_1, a_2, a_1+a_2, a_1+2a_2, 2a_1+3a_2, 3a_1+5a_ ...

随机推荐

  1. Eng1—English daily notes

    English daily notes 2015年 4月 Phrases As a side note 作为附注,顺便说句题外话,和by the way意思相近,例句 As a side note, ...

  2. 浅谈Stein算法求最大公约数(GCD)的原理及简单应用

    一.Stein算法过程及其简单证明 1.一般步骤: s1:当两数均为偶数时将其同时除以2至至少一数为奇数为止,记录除掉的所有公因数2的乘积k: s2:如果仍有一数为偶数,连续除以2直至该数为奇数为止: ...

  3. PHP数据库类

    简单封装PHP操作MySQL的类 <?php /* 类的名称:Model 类的作用:连接数据库执行sql语句 作 者:lim 更新时间:20170812 */ class Model{ //存放 ...

  4. 37 - 网络编程-UDP编程

    目录 1 UDP协议 2 UDP通信流程 3 UDP编程 3.1 构建服务端 3.3 常用方法 4 聊天室 5 UDP协议应用 1 UDP协议 UDP是面向无连接的协议,使用UDP协议时,不需要建立连 ...

  5. NoSQL-来自维基百科

    NoSQL有时也称作Not Only SQL的缩写,是对不同于传统的关系型数据库的数据库管理系统的统称. 两者存在许多显著的不同点,其中最重要的是NoSQL不使用SQL作为查询语言.其数据存储可以不需 ...

  6. caffe Python API 之Accuracy

    net.acc = caffe.layers.Accuracy(net.fc3,net.label) 输出: layer { name: "acc" type: "Acc ...

  7. Mysql自带profiling性能分析工具使用分享

    1. show variables like '%profiling%';(查看profiling信息)       2. set profiling=1;(开启profiling)   3. 执行S ...

  8. java并发编程实战笔记---(第五章)基础构建模块

    . 5.1同步容器类 1.同步容器类的问题 复合操作,加容器内置锁 2.迭代器与concurrentModificationException 迭代容器用iterator, 迭代过程中,如果有其他线程 ...

  9. HBase 入门笔记-安装篇

    一.前言 接触HBase已近半年,从一无所知到问题的解决,在数据落地方面也有了一定的了解,在此记录这半年来碰到的一些问题和对一些数据落地方面的见解,本篇主要介绍一下hbase安装方面的信息 二.安装环 ...

  10. html学习-css

    1.css初识 css 中文解释:层叠样式表,把html比作骨骼的话,css就是衣服,他的外在都能通过css来修饰,js则是肌肉,能使html动起来.产生用户交互... 1.1css样式表类型 css ...