【题解】曼哈顿模拟赛(洛谷)
前言
首先%%%所有 AK/差点AK/场外AK 的神犇!
这次出题比较仓促,题目质量或许不够高。庆幸的是数据、标程没有出问题。
办比赛的目的就是共同学习、进步,大家开心就好~
std、测试数据均已打包上传到网盘,点我下载,提取码 tb6u
接下来是题解:
A.曼哈顿计划I
一句话题意:
一颗树上每个点有权值(SG函数值),问能否选择一条链,使SG函数值异或和为零。
预备知识
不会SG函数的同学请移步这里 -> ydc老师的博客
题解
直接放神犇同学@loveyayoi的题解:
- 知识需求:sg函数,点分治
- 做过一些点分的题的同学应该一眼就能看出这是一道点分
- 做过一些博弈问题的同学应该一眼就能看出这是一道SG函数博弈
- 我们分别讨论n,k,w三个条件
n
- 对于n<=1000的情况,直接暴力DFS即可
- 对于n<=30000的情况,点分治+set/hash
k
- 通过打表可以发现一些规律
- k=1时就是普通的nim游戏,\(sg(x)=x\)
- k=2时通过打表可以发现明显的规律,如果s是偶数,sg函数有长度为s+1的循环节,值为0,1,0,1,0,1,0,1....,2,如果s是奇数,那么\(sg(x)=x\ mod\ 2\)
- k=3时,打表也可以看出规律,\(sg(x)=\lfloor \frac{x}{s} \rfloor\)
- k=4时,打表得知,
w
- w<=1000,暴力筛出sg函数即可
- w<=1e9,找规律O(1)求sg函数
复杂度
\(O(T N log N)\),假设hash达到期望复杂度\(O(1)\)
吐槽
k=5那个是逗你玩的- 某思博出题人把set卡掉了,因为hash跑的很快。
- 快去喷他。
好吧我就是那个思博出题人。(逃
这里给大家安利一种跑得很快的hash:cuckoo hash(中文名貌似叫杜鹃哈希?)。
代码实现可以看std。今后有时间应该会写一篇博文详细讲一下这个很妙的hash。
B.交易
据说是原题的弱化版啊...都怪思博出题人做题太少
一句话题意
长度为N的序列,每次询问一个区间中K小的出现次数的值,允许离线。
简要做法
题意可能比较绕,翻译成人话大概是这样的:区间里每个数字都有一个出现次数(没出现过的数字不算),然后把这些出现次数排个序,求其中的第k小。
因为可以离线,直接上简单好写的莫队算法即可。
具体操作
每次移动端点时,维护每个数的出现次数,同时维护(每个数的出现次数)的出现次数,然后通过一些套路的分块方法(O(1)修改,O(sqrt(N))查询)维护答案。
复杂度
\(O(M\sqrt N)\)
C.序列
一句话题意
给出一个长度为N的字符串,求其字典序第k的子序列(重复子序列只计数一次)。
简要做法
看到这道题,是不是想到[TJOI2015]弦论了呀,嘿嘿嘿。
由于字符集大小只有26,我们只要简单地嘿嘿嘿dp就可以得到答案了。
具体操作
首先预处理出每个位置之后遇见的第一个a-z字符的位置,然后从后往前处理出每个位置可以往后转移的子序列个数,最后逐位确定答案。
细节
2^N明显会爆int,爆ll,爆int_128...所以我们不能强行存下来。
一个好的解决方案是:设置一个大于K的值作为INF,如果一个节点的cnt大于INF,就变成INF,不再往上加了。显然这样做对答案不会造成影响。
其他
其实这是一个子序列自动机的模型。貌似网上关于这个的资料很少啊(似乎也没什么卵用
题外话
(本来想出可重/不可重两个版本的,无奈出题人太弱想不出解法,于是不了了之。如果有神犇会可重的做法,求告诉思博出题人qwq。)
D.曼哈顿计划II
一句话题意
给出一张无向图,每个点有正权,每次询问满足权值和大于等于给定值的点集的(任意两点之间最大流的最小值)的最大值
题解
直接放神犇同学@loveyayoi的题解。
- 知识需求:等价流树,带权并查集(不必要)
- 我们考虑题目中的那个乱七八糟的描述,尝试把它复述一下
- 使得任意两点\(u,v\in V_{1}\)都至少有k条互不相交的u到v的链(互不相交定义为:没有重复的边,可以重复有重复的点)
- 转述一下就是:
- 使得任意两点\(u,v\in V_{1}\)不连通都至少需要切断k条边
- 就是个最小割(最大流的建模也很显然)咯
- 然后询问就转化成了:你要选出的一些点满足工作需求,同时在原图中把这些点割成两部分所需的代价最大
- 这个东西长得就很像全局最小割,但是我们询问的不是整个图,不妨把他称作部分最小割
- 我们把这张图的等价流树构建出来,则在图中选出一些点的部分最小割的权值,等于这些点在等价流树上所形成的导出子树上所有边的最小值,证明如下。
- 我们不妨证明,部分最小割必定被包含在等价流树上的\(u\in V_{1}\)的导出子树中,且导出子树上的边权都大于等于部分最小割
- 枚举两点\(u,v\in V_{1}\),求一个u到v的最小割,则u到v的最小割就是等价流树上u到v的边权最小值,显然这些边都属于导出子树。且这个导出子树上所有的边,都会在某次枚举中取到,且显然任何一个最小割都能在某次枚举中取到,所以部分最小割必定被包含在导出子树中。
- 假设导出子树包含了比部分最小割权值更小的边,不妨取这条边的两端做一个最小割,显然这是一个满足条件的部分割,则原来的部分最小割不是最小割
- 然后还可以发现,我们对于每个询问选出的一些点一定在等价流树上构成一个点联通快,证明是平凡的,如下
- 由于原图是联通的,导出子图必然联通。如果树上的节点构成了多个联通块,不妨把属于导出子图而不属于联通块的节点都加入答案,显然部分最小割不会更差且总的工作能力上升了
- 那么我们建出等价流树,把等价流树上的边按权值从大到小排序,把询问从小到大排序,用带权并查集维护即可,最终复杂度为\(O(n^4+q)\),事实上,由于等价流树渐进复杂度过差,询问部分随便怎么处理都行,但这么写比较优雅
吐槽
- 等价流树真是玄学复杂度啊...我不是故意卡常的啊(捂脸)
结语
一场水(yuan)题赛就这么结束辣,被dalao虐场的感觉真是酸爽啊。
如果有什么更好的建议,欢迎来裱出题人。
最后祝所有省选的同学RP++!