• Goodbye 2020题解


    (Goodbye 2020)题解

    (zhanglichen 2020.12.31)

    (A.Bovine Dilemma)

    (x)轴上有(n)个点,在((0,1))位置有一棵树。两个点和这棵树可以构成一个三角形。询问可以构成三角形的面积数。

    (Solution)

    考虑到(n)的范围只有(50)(n^2)枚举每两个点之间的距离,用(set)维护一下数量。

    时间复杂度(O(n^2))

    (B.Last minute enchancements)

    给出一个长度为(n)的数组,可以对每个元素进行(+1)操作或保持不变,询问可以得到的新数组的最多不同元素数量。

    (Solution)

    对数组排序后从前往后枚举每一个不同的数。

    假设当前枚举的数是(x)。如果(x)只有一个,那么不管对它做什么操作,它对答案的贡献都是(1)。如果(x)有多个,它对答案的贡献可能是(1)(2)。考虑选择其中一个(+1),然后往后枚举。(这个+1的数可能是新的数也可能与后面已经出现的数字重合,就放到后面再统计)

    时间复杂度(O(n))

    (C.Canine poetry)

    给出一个字符串,询问最少次操作使得字符串中不包含长度大于(1)的回文字串。

    (Solution)

    考虑一个奇数长度回文串必定由一个长度(3)的回文串衍生,一个偶数长度回文串必定由一个长度(2)的回文串衍生。所以破坏所有长度为(2)和长度为(3)的回文串即可。

    时间复杂度(O(n))

    (D.13th Labour of Heracles)

    给出一棵带点权的树。

    (k)着色定义为将(k)种颜色分配给树上的每条边,不必使用每种颜色。

    颜色(x)的子图由来自原始树的分配了(x)的边组成。

    一个连通分量的权值定义为其顶点权重之和。

    将子图的值定义为其连通分量的最大权重。定义空子图的权重为0。

    (k)-值定义为所有(k)色的子图的值之和。给定一棵树,对于(1)(n-1)的每个(k),计算(k)着色的最大值。

    (Solution)

    在草稿纸上简单推导后可以发现,当(k)等于(n-1)时,答案是(ans=sum_{i=1}^nw_i*in_i)

    这里(w_i)指每个点的权值,这里(in_i)指每个点的度。

    考虑统计(k)减小后的答案,每次减去当前度大于(1)的权值最小的点的权值,同时把它当前的度数(-1),即可保证每步答案都是最优的。

    这个操作可以随便找个数据结构维护一下。

    时间复杂度(O(nlogn))

    (E.Apollo versus Plan)

    给出一个长度为(n)的数组,求:

    (sum_{i=1}^nsum_{j=1}^nsum_{k=1}^n(x_i&x_j)*(x_j|x_k))

    (Solution)

    考虑要求的柿子:

    (sum_{i=1}^nsum_{j=1}^nsum_{k=1}^n(x_i&x_j)*(x_j|x_k))

    观察柿子,发现(x_j)既和第一个部分有关,又和第二个部分有关。

    所以考虑枚举每个(x),计算它作为(x_j)对答案的贡献。

    枚举(x)的二进制的每一位,尝试计算当前这个二进制位对答案的贡献。由于是两个部分乘起来,所以考虑先写出当前这个二进制位和其他每个二进制位乘起来对答案的贡献。

    假设我们当前这个二进制位为第(i)位,枚举的另一个二进制位为第(j)位。

    (1)如果(x)在当前位为(0),那么第一个部分这一位答案就是(0),直接不考虑。

    (2)如果(x)在当前位是(1),那么第一个部分对答案的贡献可以写作(2^i*cnt_i)。这里(cnt_i)指的是二进制第(i)位为(1)的数的数量,后面同理。

    (3)如果(x)的第(j)位是(0),那么第二个部分对答案的贡献可以写作(2^j*cnt_j)

    (4)如果(x)的第(j)位是(1),那么第二个部分对答案的贡献可以写作(2^j*n)

    对每一组二进制位((i,j))讨论上述四种情况,就是单个数(x)作为(x_j)对答案的贡献。

    (n)的范围是(5*10^5),所以对每个(x)强行(60*60)枚举二进制位必然会超时。这里考虑优化。

    观察推出来的情况可以发现,第二个部分对答案的贡献可以事先算好,这就优化掉了一维时间复杂度,顺利通过。

    时间复杂度(O(300n))

    (F. Euclid's nightmare)

    给出(n)(m)维向量,每一位是(0)(1)。每个向量互不相同,把这个向量集合称为(S)

    题目保证每个向量最多(2)位是(1)

    定义(2)个向量(u)(v)相加可以变成(1)个新的向量(w)(w_i=(u_i+v_i)mod2)

    这个定义可以衍生到多个向量叠加成一个新的向量。

    现在请你求出一个向量集合(T)的大小,(T)里的所有向量都可以通过从(S)里取一些向量相加得到。

    同时请你确定一个最小数量的向量集合(S'),使得仅由这些向量可以得到(T)

    (Solution)

    考虑从前往后依次算每个向量对答案的贡献。

    推导后发现,当前面有几个向量加起来等于这个向量的时候,这个向量对答案就没有影响,否则就会使答案(ans=ans*2+1)

    现在考虑如何判断是否存在向量集合使得这些向量加起来为当前向量。在草稿纸上反复试验后发现可以用并查集维护这个过程。

    为了方便操作,我们把每一个只有一维的向量的第(0)位改成(1)

    然后每加入一个向量,先看它存在的(2)个维度是不是在一个集合内,如果是,说明存在一组向量可以抵消它。

    然后合并当前的(2)个维度所在的集合。最后记得考虑一下空集合即可。

    时间复杂度(O(nlogn))

  • 相关阅读:
    学习Timer定时器
    C++ 延时等待(sleep/timer/wait)
    MFC学习问题总结
    node.js
    总结
    关于Windows
    关于数组
    每周一次
    每周一次
    每周一次
  • 原文地址:https://www.cnblogs.com/zhanglichen/p/14218313.html
Copyright © 2020-2023  润新知