首页 > 其他分享 >CF1917F Construct Tree 题解

CF1917F Construct Tree 题解

时间:2023-12-29 21:01:22浏览次数:29  
标签:std le int 题解 Tree Construct leq right 直径

Description

给你一个数组 \(l_1,l_2,\dots.l_n\) 和一个数字 \(d\)。问你是否能够构造一棵树满足以下条件:

  • 这棵树有 \(n+1\) 个点。
  • 第 \(i\) 条边的长度是 \(l_i\)。
  • 树的直径是 \(d\)。

只需要判断是否有解即可。

\(2\le n\le2000,1\le d\le 2000,1\le l_i\le d\)。

Solution

先把 \(l\) 从大到小排序。

容易发现把直径拉出来后,其他不在直径上的边 \(l_k\) 挂在直径的点上要满足 \(l_k\leq \min\{L,d-L\}\),其中 \(L\) 和 \(d-L\) 分别是直径上挂的点左右的长度和。

所以肯定是把不在直径上的边以类似菊花图的形式尽可能挂在中间,使得所有 \(l_k\leq \min\{L,d-L\}\)。

如果 \(l_n>d\) 显然无解。

如果 \(l_n>\left\lfloor\dfrac{d}{2}\right\rfloor\),则它一定不能是挂着的边,也就是一定在直径上,这时候只要判断 \(l_1,l_2\dots. l_{n-1}\) 都 \(\leq d-l_n\) 并且能够选出某些数和为 \(d-l_n\)。

如果 \(l_n\leq\left\lfloor\dfrac{d}{2}\right\rfloor\),并且 \(l_n\) 在直径上,则其他点一定能全挂上去,所以只要判断能否有若干个和为 \(d-l_n\) 即可。如果 \(l_n\) 不在直径上,那么就需要保证 \(\min\{L,d-L\}\geq l_n\),所以直接设 \(f_{i,j}\) 表示左边和为 \(i\),右边和为 \(j\) 是否可行即可求出。

时间复杂度:\(O(nd^2)\),过不了。

但是注意到 \(f_{i,j}\) 的转移只有 \(0/1\),所以可以 bitset 优化至 \(O\left(\frac{nd^2}{\omega}\right)\)。

Code

#include <bits/stdc++.h>

// #define int int64_t

const int kMaxN = 2e3 + 5;

int n, d;
int a[kMaxN];
std::bitset<kMaxN> f[kMaxN];

void dickdreamer() {
  std::cin >> n >> d;
  for (int i = 1; i <= n; ++i)
    std::cin >> a[i];
  std::sort(a + 1, a + 1 + n);
  if (a[n] > d / 2) {
    if (a[n - 1] > d - a[n]) return void(std::cout << "No\n");
    f[0].reset();
    f[0][0] = 1;
    for (int i = 1; i < n; ++i)
      f[0] |= (f[0] << a[i]);
    std::cout << (f[0][d - a[n]] ? "Yes\n" : "No\n");
  } else {
    for (int i = 0; i <= d; ++i)
      f[i].reset();
    f[0][0] = 1;
    for (int i = 1; i < n; ++i) {
      for (int j = d; ~j; --j) {
        f[j] |= (f[j] << a[i]);
        if (j >= a[i]) f[j] |= f[j - a[i]];
      }
    }
    bool ans = f[0][d - a[n]];
    for (int i = a[n]; i <= d - a[n]; ++i)
      ans |= f[i][d - i];
    std::cout << (ans ? "Yes\n" : "No\n");
  }
}

int32_t main() {
#ifdef ORZXKR
  freopen("in.txt", "r", stdin);
  freopen("out.txt", "w", stdout);
#endif
  std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
  int T = 1;
  std::cin >> T;
  while (T--) dickdreamer();
  // std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
  return 0;
}

标签:std,le,int,题解,Tree,Construct,leq,right,直径
From: https://www.cnblogs.com/Scarab/p/17935661.html

相关文章

  • 【题解】BZOJ 4403序列统计
    tg.BZOJ4403序列统计pj.BZOJ4403序列统计没啥用的题解\(QWQ\)——无脑思考首先要想怎么求单调不上升序列的个数,因为可能会有重复的数,所以不能直接用排列组合。那这道题怎么打呀?我不知道啊\(\dots\)\((~:\)因为原来是单调不下降序列,将第\(i\)位上的数加\(i\),于是......
  • CF1806F GCD Master 题解
    题目链接EasyversionHardversion题目解法参考DeaphetS的题解很有意思的题,感觉\(F1\)不到\(*2900\),\(F2\)超过\(*2900\)F1简化题目中的操作:把\(n\)个数放到\(n-k\)组中,求\(\max(\sum\)每组\(a_i\)的\(\gcd)\)首先考虑所有数互不相同的情况结论1:把\(k+......
  • [CF30E] Tricky and Clever Password 题解
    [CF30E]TrickyandCleverPassword题解注意到一个合法字符串首尾相同,考虑用S的反转和S跑KMP。对于只有一个串,暴力manacher即可。匹配到某一位置\((i,j)\)时,查询区间最长的奇回文串长度,用二分+ST表解决,因为回文串不能超过区间长度。//Problem:TrickyandCle......
  • P9994 [Ynoi Easy Round 2024] TEST_132 题解
    题解怎么都是用暴力日过去的啊。思路考虑根号分治,设阈值为\(B\)。对于第二维出现次数超过\(B\)的,我们可以在修改时暴力更改,这部分复杂度为\(O(\frac{nm}{B})\)。对于第二维出现次数小于\(B\)的,我们可以在修改是打标记,查询时遍历一遍,这部分的复杂度为\(O(mb)\)。大多数......
  • P9995 [Ynoi2000] rspcn 题解
    思路比较典的ODT题目。发现排序是一个非常有性质的操作。它对区间的更改与颜色段均摊差不多。那么我们可以想到用ODT来维护这一整个序列。具体的,区间排序操作可以用ODT维护每次排序产生的段,每段用线段树维护排序后的结果。每次修改就可以进行线段树的分裂与合并。如......
  • P9991 [Ynoi Easy Round 2023] TEST_107 题解
    思路题目即要求删除区间中的一个或多个颜色。考虑假如枚举删除颜色\(k\)。那么在\(l,r\)中的答案为:\[\max_{i=1}^{m+1}a_i-a_{i-1}\]其中\(a_i\)为颜色\(k\)在\(l\simr\)中的出现位置,\(a_{0}=l,a_{m+1}=r\)。可以分类讨论。答案为\(a_1-l\),那么只需要维护\(......
  • AT_abc020_c 题解
    链接(atcoder)链接(luogu)简单算法组合(?算法一爆搜,时间复杂度\(O(2^{n\timesm}\timest)\),不能通过此题。算法二考虑二分\(t\),然后暴搜,时间复杂度\(O(2^{n\timesm}\timeslog2(t))\),不能通过此题。算法三考虑二分\(t\),然后暴记忆化搜索,时间复杂度\(O(n\timesm......
  • CF1234F 题解
    blog。小清新题,下文\(V=20\)即值域。反转操作,本质就是选两个不相交连续段拼起来。显然合法的最终串长度一定\(\leV\)。将这些合法串预处理出来,那么每个串都对应一个「字母集合」。随便DP一下,求出所有集合中,的最大的合法「字母集合」大小。\(dp_{\smallU}\)就是只选一......
  • CF1917F Construct Tree 题解
    题目链接:https://codeforces.com/contest/1917/problem/F题意有\(n\)条长度\(l_i\)的边,问它们是否能组成一棵\(n+1\)个节点的树,使得树的直径长度为\(d\)。\(n,d\le2000\)。题解首先当然要存在一个边集\(D\),使得\(\sum\limits_{i\inD}l_i=d\),这可以使用背包......
  • 在不使用内置函数和中间变量的情况交换数字LeetCode力扣题解面试题16.01
    #异或法#Kotlin```KotlinclassSolution{  funswapNumbers(numbers:IntArray):IntArray{    numbers[0]=numbers[0]xornumbers[1]    numbers[1]=numbers[1]xornumbers[0]    numbers[0]=numbers[0]xor......