Codeforces1917F - Construct Tree
1.CW初中-C0102B(加强版)(CF1720D2-Trie树)2.CW初中-C0106D3.Luogu-P4654-[CEOI2017] Mousetrap4.2023.08.07模拟赛题解5.2023.08.21 模拟赛B题6.CW高中-C0296D7.Codeforces Edu 154 (A-E)8.Codeforces Pinely Round 2 (D~G)9.Atcoder-ABC317G-Rearranging10.Atcoder-ARC165F-Make Adjacent11.Codeforces1870F-Lazy Numbers12.CSP2023 题解13.CW高中-C0389B14.[PA2021] Wystawa15.CW高中-C0443D16.Codeforces1917E - Construct Matrix
17.Codeforces1917F - Construct Tree
18.Atcoder Xmas Contest 2022 H - Happy Game19.CW高中-C0452B20.CW高中-C0486A21.QOJ #1280.Fibonacci Partition/Fibonacci性质大杂烩22.图论杂题23.QOJ #1285.Stirling NumberCodeforces1917F - Construct Tree
Problems
给一个长度为 \(n\) 的序列 \(l\) 和 \(d\)。
要求判断是否可以构造出一颗节点数为 \(n+1\) 的树,满足 \(l\) 的每一个元素唯一对应为一条边的长度,并使整棵树的直径长度恰好为 \(d\)。
Solution
不妨令 \(l_1 \le l_2 \le \cdots \le l_n\)。
考虑必须要找出 \(l\) 的子集使得其和为 \(d\)。同时考虑如何构造出一棵可行的树。
把选出的部分 \(l'\) 展成一条链,可以发现如果最后满足答案,充要条件是存在一个点,使得所有未被选中的边都可以直接连在这个点上,且直径仍然为最初 \(l'\) 展出的链。
设这个点为 \(v'\),链的两端分别为 \(v_1,v_2\),发现满足条件当且仅当:
\[\max\{\mathrm{distance}(v',v_1),\mathrm{distance}(v',v_2)\} + l_e\le d
\]
其中 \(e\) 为任意一条没有选中的边。
发现实际上可以直接动态规划。固定分界点,记录以上的两个值,考虑怎么转移。
有点说不清楚,对着代码讲吧。(出题人的实现很牛,照搬过来的)
bitset < D > f[D >> 1];
void Push (int x){
for (int i = d >> 1;i >= 0;-- i){
if (i + x <= (d >> 1))
f[i + x] |= f[i];
f[i] |= f[i] << x;
} // 正常转移
}
void WORK (){
f[0][0] = 1;
int id = 1;
for (int i = 1;i <= (d >> 1);++ i){ // 钦定前面一维的长度不会超过 d/2
while (id <= n && ! (l[id] ^ i))
Push (l[id]), id ++;
res = 0;
for (int j = id;j <= n;++ j)
res += l[j];
if (res <= d - i && f[i][d - i - res]){
// 这里实际上在考虑前一维为 i 的情况,所以可以不需要先转移后面。
// 小于等于 i 的边此时一定可以挂在分界点上,或者参与转移。
// 大于 i 的边此时不能挂在分界点上,
// 而固定前一维为 i ,所以大于 i 的边此时一定会挂在后一维的链上。
// 通过 d 算另一维的大小,再减去还没有考虑转移的(就是大于 i 的)边的长度和,判断是否存在即可
puts ("Yes");
return ;
}
}
puts ("No");
}
需要用 \(\textrm{bitset}\) 。
时间复杂度 \(O(\frac{nd^2}{w})\)。\(w\) 为 \(\textrm{bitset}\) 的位数。
Code
#include <bits/stdc++.h>
using namespace std;
const int N = 2005, D = 2005;
bitset < D > f[D >> 1];
int T, n, d, sum, res, l[N];
void Push (int x){
for (int i = d >> 1;i >= 0;-- i){
if (i + x <= (d >> 1))
f[i + x] |= f[i];
f[i] |= f[i] << x;
}
}
void WORK (){
scanf ("%d%d", &n, &d);
sum = 0;
for (int i = 1;i <= n;++ i){
scanf ("%d", &l[i]);
sum += l[i];
}
if (sum == d){
puts ("Yes");
return ;
}
sort (l + 1, l + n + 1);
for (int i = 0;i <= (d >> 1);++ i)
for (int j = 0;j <= d;++ j)
f[i][j] = 0;
f[0][0] = 1;
int id = 1;
for (int i = 1;i <= (d >> 1);++ i){
while (id <= n && ! (l[id] ^ i))
Push (l[id]), id ++;
res = 0;
for (int j = id;j <= n;++ j)
res += l[j];
if (res <= d - i && f[i][d - i - res]){
puts ("Yes");
return ;
}
}
puts ("No");
}
int main (){
scanf ("%d", &T);
while (T --)
WORK ();
return 0;
}
本文作者:saubguiu
本文链接:https://www.cnblogs.com/imcaigou/p/17926858.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步