清华集训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\)的因子数,\(\tau(n)\)表示\(n\)的倍数数(\(m\)以内)。
对于操作1,直接维护当前加入的位置的信息即可,复杂度\(\mathcal O(\sigma(x) + \log m)\)
对于操作2,考虑把所有有影响的数取出并按照位置为关键字排序,依次更新dp值和f数组(注意顺序一定要对),由于所有有影响的数一定是加入的数的倍数,所以复杂度为\(\mathcal O(\tau(x) (\log m + \log n) + \sum_{x | g} \tau(g) + \log m)\)
对于操作3,和1类似,直接删除这个位置的信息即可,复杂度\(\mathcal O(\log M)\)
对于操作4,和2类似,\(\mathcal O(\tau(x) (\log m + \log n) + \sum_{x | g} \tau(g) + \log m)\)
由于有每个数最多出现10次的保证,所以总复杂度还是可以的。

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

题意

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

\[f(n) = \begin{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 = \begin{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寥寥几行,预处理独领风骚)

posted @ 2019-08-06 10:30  psimonw  阅读(336)  评论(0编辑  收藏  举报