2021HDU暑期多校第三场¶
排名 | 当场过题数 | 至今过题数 | 总题数 |
---|---|---|---|
66/750 | 5 | 11 | 12 |
A¶
upsolved by JJLeo
题意¶
给出一棵 \(n\) 个节点的树,每个节点有一个商品,价格为 \(p_i\)。
\(q\) 次询问,每次给定树上一条路径,初始携带 \(m_i\) 元,走到一个点如果钱就够就买一个商品,如果不够就不买,问最后剩多少钱。
(\(1 \le n,q \le 10^5\),\(1 \le p_i,m_i \le 10^9\))
题解¶
首先将所有询问离线,并拆分成从下往上走 (到 lca) 和从上往下走两部分。
考虑先全部处理出每个询问走到 lca 时还剩多少钱,再全部处理出每个询问从 lca 走到终点还剩多少钱,下面以向上走为例:
重链剖分,将每个询问分割为 \(O(\log n)\) 段重链,标记每段开始和结束的位置。逆序枚举 dfn 序,到了一个点先将这个点开始的所有询问加入数据结构,然后将数据结构中所有值 \(\ge m_i\) 的全部减少 \(m_i\),然后将这个点结束的所有询问移出数据结构,由于重链的 dfn 序是连续的,这样做可以保证正确性。
考虑使用 FHQ-Treap,所有询问按照其值排序,对于一次操作:
-
对于所有 \(<m_i\) 的元素,不需要进行操作。
-
对于所有 \(\ge m_i\) 的元素,分裂后不能直接打标记,因为合并时要保证其中一颗元素都小于另一颗,减去 \(m_i\) 后可能会小于之前 \(<m_i\) 的元素,考虑如下的 trick:
- 对于 \([m_i,2m_i)\) 的元素,将其分裂出来暴力一个个把权值减了再插回去,这样做一次会使得其值减少一半,因此对于每个询问至多会被执行 \(O(\log p_i)\) 次。
- 对于 \(\ge 2m_i\) 的元素,其减去 \(m_i\) 也不会小于之前 \(<m_i\) 的元素,直接打标记即可。
取出一个元素可以通过记录每个节点的父亲得到对应点的排名,从而使用对于 size 的分裂将其取出。
向下走和向上走是完全类似的,只不过初值变了,且改为正序枚举 dfn 序。总时间复杂度为 \(O(n \log ^ 2 n)\)。
B¶
upsolved by 2sozx JJLeo
题意¶
给定一颗 \(n\) 个节点的树,一共有 \(m\) 个人,每个人固定一个起点,有三个旅行方案,每个方案有各自的终点和各自的代价,问是否可以让每人选一个方案使得所有人经过的路径不相交,如果可以最小化代价之和。(\(1 \le n \le 2 \times 10^5\),\(1 \le m \le 10^5\))
题解¶
赛时做法:
忘了。
可惜最后没时间了,没写完,经典赛后过题。
C¶
solved by JJLeo
题意¶
给定两个串 \(s,t\),问 \(t\) 和多少个 \(s\) 的子串至多有 \(k\) 个不同的字符,对 \(k=0,1,2,\ldots,|t|\) 给出答案。
字符集为 0
到 9
,同时还有一个通配符。(\(1 \le |t| \le |s| \le 2 \times 10^5\))
题解¶
字符集很小,很经典的 FFT 套路题,枚举每个字符,相应位置设为 \(1\),否则是 \(0\),卷起来即可得到每个位置的匹配数量。
对于通配符,也将其设为 \(1\),但是两个通配符匹配会被算 \(10\) 遍,因此再单独对通配符做一次匹配,也就是只将通配符的位置设为 \(1\),减去 \(9\) 倍的这个值即可。
D¶
solved by 2sozx Bazoka13 JJLeo
题意¶
\(\sum\) 签到,虽然是签到,但是 HDU 不能有快读和 fread()
!
题解¶
因为这题罚时裂了,离谱 HDU \(\sum\) 好吧。
E¶
upsolved by JJLeo
题意¶
平面有向图,\(1\) 能到所有点,所有点都能到 \(n\),每个点有一个权值,选一些点最大化权值之和,要求所选点任意两个点都不可达,多解要求所选点的字典序最小。(\(1 \le n \le 10^5\))
题解¶
需要利用平面图的性质,从 \(1\) 开始分别顺时针和逆时针 dfs 所有点,记每个点的出栈序为 \(a_i,b_i\),则 \(i\) 可以到达 \(j\) 当且仅当 \(a_i > a_j \land b_i > b_j\)。
充分性显然,\(i\) 如果可以到达 \(j\) 那么不管如何 dfs,前者出栈序必然大于后者。
必要性则考虑其逆否命题,如果 \(i\) 不可达 \(j\),要么 \(j\) 可达 \(i\),那么 \(a_i < a_j \land b_i < b_j\);要么 \(j\) 不可达 \(i\),如果 \(a_i > a_j\) 那么把遍历顺序反过来即 \(b_i < b_j\),反之亦然。从而如果 \(i\) 不可达 \(j\) 则 \(a_i > a_j \land b_i > b_j\) 不成立。
因此将点按 \(a_i\) 排序后相当于求权值最大的 \(b_i\) 降序子序列,如果不要求字典序最小直接树状数组 \(O(n \log n)\) 就可以求。每个选点方案等价于一个 \(01\) 串,因此可以用动态开点线段树存储,每次只会新增一个点,比较时在线段树上二分,找到第一个不同的位置即可得到大小关系,因此可以在 \(O\left(n \log ^2 n\right)\) 的复杂度内完成。
一个小 trick 是,相比去年 claris 那场 hdu 多校类似用动态开点线段树存方案的题,这里不需要维护哈希值,因为对于 \(01\) 串每个位置,最多只添加一次,因此两个节点不同等价于它们对应的串不同。
F¶
upsolved by JJLeo
题意¶
两侧各 \(n\) 个点,\(n^2-m\) 条边,左侧点权值为 \(a_i\),右侧点权值为 \(b_j\),一条边的边权为 \(a_i+b_j\),求匹配数为 \(1,2,\ldots,n\) 的最大权匹配。(\(1\le n \le 4000\),\(1 \le m \le 10000\))
题解¶
考虑模拟费用流,每次增广一个单位流量,将左侧点按权值从大到小排序后,依次选择能从源点到达的 (也就是还没有被匹配的) 进行 bfs,对右侧每个还能到达汇点的点记录最先被哪个左侧哪个点能到达 (不是多源 bfs,遍历完一个起点再加入下一个起点,每个点只遍历一次),这样就可以得到目前这个点可以匹配的最大权值,遍历所有右侧点取最大的权值将其作为这次的增广路,将权值加入答案,同时模拟网络流改变增广路上的容量,并为其增加反向边。
需要注意的是这题是以补图的形式给出的,需要使用补图 bfs:
将目前没经过的点存入链表,每次遍历链表尝试从当前点到达,如果不存在这条边则跳过,否则将该点从链表中删除并到达该点。
因为只有 \(O(m)\) 条边没有,所以跳过的时间复杂度为 \(O(m)\),总时间复杂度为 \(O(n+m)\)。
需要注意本题中链表中只能存放右边的点,右边到左边的边可以通过当前的匹配情况得知,如果加入复杂度就不对了。一共增广 \(O(n)\) 次,每次时间复杂度为 \(O(n+m)\),总时间复杂度为 \(O(n^2+nm)\)。
H¶
upsolved by
题意¶
题解¶
I¶
solved by 2sozx JJLeo
题意¶
\(n \times n\) 的格子图,从左上走到右下,只能往下或往右,每个格子有两个权值 \(a_{i,j}\) 和 \(b_{i,j}\),最终权值为经过所有格子的 \(\left(\sum a_{i,j}\right)\left(\sum b_{i,j}\right)\),最大化这个权值,保证数据随机。(\(1 \le n \le 100\))
题解¶
随机乱搞,每个状态记录约 \(100\) 个当前 \(\left(\sum a_{i,j}\right)\left(\sum b_{i,j}\right)\) 最大的状态就可以通过了。
J¶
upsolved by JJLeo
题意¶
\(n\) 个点 \(m\) 条边的无向图,每条边有两个权值 \(c_i\) 和 \(d_i\),分别为正常权值和折扣权值,问恰好使用 \(0,1,\ldots,n-1\) 条折扣权值的最小生成树的权值和。(\(2 \le n \le 1000\),\(n-1 \le m \le 2 \times 10^5\),\(1 \le d_i \le c_i \le 1000\))
题解¶
拆成 \(2m\) 条黑白边,显然原本的一条边拆成的两条边不会同时被选,因此问题等价于恰好选 \(k\) 条黑边的最小生成树,这是 wqs 二分的入门题。
注意边权很小,这意味着这个下凸函数相邻两点的斜率绝对值也不会很大,可以直接将斜率 \([-1000,0]\) 能切到横坐标最小 / 最大的点算出来,最小就优先选白边,最大就优先选黑边,设为 \([l,r]\),那最终选 \([l,r]\) 条黑边的答案就可以得到了,显然最终遍历所有斜率那么可以覆盖横坐标为 \([0,n-1]\) 的所有整点。
设 \(c=1000\),这样需要算 \(c\) 次 \(O(m \log m)\),可以先各自对黑边白边做一次最小生成树,那么只有这些边才可能被用上,可以将边数减少到 \(O(n)\)。总时间复杂度为 \(O(cn \log n+m \log m)\)。
L¶
upsolved by JJLeo
题意¶
\(n\) 个数 \(a_1,a_2,\ldots,a_n\),相邻数不能同时选,下标之差为 \(k\) 的数不能同时选,且至少选一个数。一个方案的权值是所有选了数的乘积,求所有方案权值的和。(\(2\le k < n \le 300\))
题解¶
考虑两个算法:
- 算法一:直接记录前 \(k\) 个元素的选择情况,从左往右扫一遍,时间复杂度为 \(O\left(n2^k\right)\)。
- 算法二:将序列变成一个 \(k \times \left\lceil\dfrac{n}{k}\right\rceil\) 的矩阵,第 \(i\) 个位置在 \(\left(i \bmod k,\left\lfloor\dfrac{i}{k}\right\rfloor\right)\) 处 (0-indexed),强行钦定最后一列从下往上 \(k \left\lceil\dfrac{n}{k}\right\rceil-k\) 个位置不能放数。那么这个矩阵上下左右四个位置不能同时放数,同时最后一行第 \(i\) 列和第一行第 \(i+1\) 列也不能同时放数,因此记录第一行的摆放情况以及当前的轮廓线 (第一次知道这个 dp 原来这个也叫轮廓线)。具体来说就是假设 dp 到第 \(i\) 行第 \(j\) 列,那么状态就是第 \(i\) 行前 \(j\) 个位置是否放数以及第 \(i-1\) 行前 \(j\) 个位置是否放数,最后利用最后一行和第一行的状态判断是否合法,时间复杂度为 \(O\left(n2^{\frac{2n}{k}}\right)\)。
利用根号分治,时间复杂度可以达到 \(O\left(n2^{\sqrt{2n}}\right)\),但还是太慢了,注意到所有的二进制状态一定是独立集,数量是斐波那契数列,约为 \(O\left(1.618^k\right)\),因此 dfs 出所有状态即可将复杂度降为 \(O\left(n1.618^{\sqrt{2n}}\right)\)。
记录¶
0h:开始分题,看K签到ZYF冲,然后CSK看G签到留着给ZYF写,写完了有人过D了,MJX、CSK看着也是道sb题,CSK冲D,T了一发,然后开始了罪恶的垃圾HDU测评机器。
1h:ZYF去冲C,秒过,继续卡死D,把STL全换了,加上快速读入还是T,把排序优化还是T,加上fread后WA了,觉得是算法有点问题。
2h:想了想I,说是数据随机,MJX想就乱搞一下大概就行,喂给ZYF,ZYF WA了一发换了个乱搞方法就过了,然后过了。翻了翻Clarification。
换成scanf过了,HDU还不支持fread,西内!
3h:想了那个最小生成树和类似费用流的那题,没想出来,挂机一小时。
4h:想了个B的解法,看起来很对,ZYF冲了,没冲完,不知道哪有问题,寄了寄了。
总结¶
- MJX:B最后破案了,当时问ZYF那个查询是单点的么,其实不是,下次不清楚的一定要问好,最后时刻太紧张了很容易写错。
Dirt¶
D(+10):HDU是逆天
I(+1):换了个乱搞算法,没啥办法