zoukankan      html  css  js  c++  java
  • 清华集训2017刷题记录

    2322. 「清华集训 2017」Hello world!

    题意

    一棵树每个点有点权,每次可以选择两个点(s, t),选择步长为(k),从(s)跳到(t)(不足(k)步直接到(t)),并且有两种操作,一种是将经过所有点的点权都开根后下取整,一种是统计经过所有点的点权和。
    点数(leq 50000)
    询问(leq 400000)
    点权(in [1, {10} ^ {13}])

    题解

    考虑在一个序列上的做法。这个开根号本来就是一个经典操作。
    可以考虑对步长(k)大小分块。设阈值为(S)
    如果(k geq S),则考虑直接暴力跳,暴力修改,有效的修改最多(mathcal O(n log log V))次,如果一个数变成了1,就用并查集维护他所在的连续的1的最后位置(就是维护一段连续的1)。
    如果(k < S),则考虑建立(k)个树状数组,查询修改都要依赖这个树状数组(包括上一种情况的修改,同时也要更新树状数组)。
    如果把并查集复杂度当做常数,则复杂度是 (mathcal O(n log log V S log n + Q frac{n}{S} log n + Q S log n))
    考虑在树上做,就要支持查询某一个节点的(k)级祖先,我们把一个原图的极大子集叫做(k)级树当且仅当它是一棵树,且父子节点在原树上距离为(k)
    考虑从(s)(t)的路径要分解成两段竖直路径(一端是另一端的祖先的路径),然后对于每一段路径上的点,都是(k)级树上的一条连续路径。
    前一种情况还是可以用类似方法做,变化不大;
    后一种情况,要在对应(k)级树上修改或查询某段路径的权值。这个可以直接无脑树剖,也可以用树上差分做。(实测树剖更快。。。)
    若使用树上差分,复杂度为 (mathcal O(n log log V S log n + Q frac{n}{S} log n + Q S log n))
    实测(S)取20时最优。。(咋看都不像,都是常数惹的祸)
    另外吐槽一句,树上差分什么的竟然没有想到,看来已经不会了。。
    upd:我错了,uoj上过不去因为(S)开小了。。。

    2323. 「清华集训 2017」小 Y 和地铁

    题意

    给出(n)个点排成一条直线,每个点都有一个标号,相同标号的点最多只有2个,且相同标号的点之间有一条连边。
    最小化所有连边的交点(包括(n)个点连成的直线,相交在端点处不算)。

    题解

    神仙题,官方题解来一波(当然是别人blog里的……)。


    话说回来当然是极有道理的……

    2324. 「清华集训 2017」小 Y 和二叉树

    题意

    给出一个每个点度数不大于3的树,求字典序最小的中序遍历。

    题解

    题外话:不得不说,这个部分分很有帮助,然后这道题的详细证明也很有意思。
    考虑字典序要最小,逐位确定法。最左的点肯定是度数不为3的点,设改点为(st)
    那么我们从这个点开始做一个构造过程。

    (x)是当前节点,(p)是上一个节点(如果(x)是初始节点(p)就是一个虚点),(u)(v)(x)的其他两个节点(可能有空节点)。
    我们还要考虑一件事情:(p)是否为根。根的确定是一件比较重要的事情。然后就有了这种情况。

    讨论之前,先设(mn_{x, 0})表示(x)的子树中的最小值(以(st)为根),(mn_{x, 1})表示(x)的子树中度数不为3的最小值(以(st)为根)。
    对于后一种情况,因为比较简单。
    1.如果除了(p)(x)只有一个子节点(u)
    (x < mn_{u, 1}),则将(u)作为(x)的右儿子;否则将(u)作为(x)的左儿子;
    2.如果除了(p)(x)有两个子节点(u, v)
    (mn_{u, 1} < mn_{v, 1}),则将(u)作为(x)的左儿子,(v)作为(x)的右儿子;否则将(v)作为(x)的左儿子,(u)作为(x)的右儿子;
    对于前一种情况,比较复杂。
    1.如果除了(p)(x)只有一个子节点(u)
    (mn_{u, 1} < u),则将(u)作为(x)的右儿子更优(因为不能用度数为3的节点作为根,向上没有向下优);
    (mn_{u, 1} geq u),则将(u)作为(x)的父节点更优;(这个情况的证明咕了,原因是博主想去观看IOI直播了……大概可以用归纳证明)
    2.如果除了(p)(x)有两个子节点(u, v)
    (mn_{u, 1} < mn_{v, 1}),则将(u)作为(x)的右儿子,(v)作为(x)的父节点;否则将(v)作为(x)的右儿子,(u)作为(x)的父节点。
    然后就做完了。
    题外话:问这个(mn_{x, 0})有什么用,大抵是没有用的,只是因为博主脑抽了,写了题解才发现。

    2326. 「清华集训 2017」简单数据结构

    题意

    一个序列,支持四种操作:
    1.在左端加入一个数;
    2.在右端加入一个数;
    3.删除最左端的数;
    4.删除最右端的数;
    求每个操作后最长上升倍数子序列的长度和不同的开头数
    保证每个操作前后序列非空,每种数只会出现在一个位置上。一个数出现次数不超过10。
    数的大小是({10} ^ 6)级别的。

    题解

    一看就是套路题。先预处理一个数的倍数和约数。总和是(mathcal O(m log m))级别的。
    注意到一个数同时只会在一个位置出现,很显然可以以位置为某个数的标记。
    考虑dp数组(dp_i)表示以(i)位置开头的最长上升倍数子序列的长度,(f_{i, j})为以(i)位置开头,上一个位置的dp值为(j)的个数。注意到我们要求的子序列长度在(mathcal O(log n))级别,所以可以这么做。
    (sigma(n))表示(n)的因子数,( au(n))表示(n)的倍数数((m)以内)。
    对于操作1,直接维护当前加入的位置的信息即可,复杂度(mathcal O(sigma(x) + log m))
    对于操作2,考虑把所有有影响的数取出并按照位置为关键字排序,依次更新dp值和f数组(注意顺序一定要对),由于所有有影响的数一定是加入的数的倍数,所以复杂度为(mathcal O( au(x) (log m + log n) + sum_{x | g} au(g) + log m))
    对于操作3,和1类似,直接删除这个位置的信息即可,复杂度(mathcal O(log M))
    对于操作4,和2类似,(mathcal O( au(x) (log m + log n) + sum_{x | g} au(g) + log m))
    由于有每个数最多出现10次的保证,所以总复杂度还是可以的。

    2328. 「清华集训 2017」避难所

    题意

    (b)进制下,找一个数,满足(f(n) > n)
    (f(n))由递归定义

    [f(n) = egin{cases} f(frac {n}{k}) * b + k, & n geq b cap k = max {k_0: k_0 | n cap k_0 < b } \ n, & n < b \ end{cases} ]

    如果最小的(n)在十进制下超过({10} ^ {18}),输出-1。

    题解

    结论题……(还是我菜了)
    注意到当(b)足够大时,取
    (x)使得((x - 1) ^ 2 leq b cap x ^ 2 > b)(y)使得(y ^ 3 leq b cap (y + 1) ^ 3 > b)
    然后就找到了一个解(n = {x * y, x * y, x * y})(对应的(f(n) = {y ^ 3, x, x, x}))。
    注意到在(b)足够大时这是不错的,因为(x * y leq b),而(b leq {10} ^ 5),满足了(n)的各数位乘积不超过({10} ^ {18})
    (b leq 130)时暴力找解即可(解的形式都是({x, x, y})或者({x, y, y}),我也不知道为什么……)。

    2330. 「清华集训 2017」榕树之心

    题意

    开始你在1号点(根),每次你可以选择一个未扩展节点(v),连上有关的边((u, v))(满足(u)是已扩展节点),然后向(v)的方向移动一步。
    问最后是否能停在某个节点上。

    题解

    考虑一个性质:在一棵树的两棵不同子树中分别进行一次操作贡献可以抵消。
    (dlt_x)为在(x)的子树里,最少能产生多少个多余为扩展的点(不包括(x))。
    显然应该考虑(x)的最大子树。设为(y)
    则有

    [dlt_x = egin{cases} (siz_x - 1) mod 2, & dlt_y + 1 leq siz_x - siz_y - 1 \ dlt_y + 1 - (siz_x - siz_y - 1), & else \ end{cases} ]

    最后如果(dlt_1)(0),最后就无法走到1号点上。
    考虑是否能停在其他节点上。
    由于从根到这个节点的这条路径是一定要走的,感性理解一下把这条路径缩成根和原来是等价的(可以把这条路径上的边看成是调整平衡的工具,也算有了斡旋的余地吧)。
    然后做一个换根dp即可。

    2331. 「清华集训 2017」某位歌姬的故事

    题意

    给一些限制,表示一个区间([l, r])内最大数为(x),所有数都在([1, A])内,求合法序列的数量。

    题解

    如果没有(x)相同的情况,那就是个水题。
    考虑一般解法。设(c_i)为位置(i)的最低限制。
    按照(c_i)的大小,我们可以把原来的序列重新排序,如下图。

    就像上图需要注意的是,重排后,1,2,3应该要归于同一限制的。反正这种东西写离散化也是烦的要死。
    现在考虑一段相同高度的限制,如图。

    应该把无用区间删去,然后区间就是随左端点单调,右端点单调的了。
    然后做个nmdp即可。。。(dp寥寥几行,预处理独领风骚)

  • 相关阅读:
    CSS之EM相对单位
    html之canvas
    JS之事件监听
    html之iframe
    [转]nodejs中的process模块--child_process.exec
    [转]阮一峰:理解RESTful架构
    JS性能之滚动条之外的其他部分
    JS性能之setTimeout与clearTimeout
    CSS禁止鼠标事件---pointer-events:none
    打开文件、文件操作、管理上下文
  • 原文地址:https://www.cnblogs.com/psimonw/p/11295072.html
Copyright © 2011-2022 走看看