先来个小问题?
MysteryMan 是谁呢?
关于这点,我只能告诉你无可奉告,你们不高兴也不行。
好吧其实是一个2009年左右的不愿透露姓名的OI选手……
Day1
UOJ拯救计划
from MysteryMan, 题解 by ydc
大家好,这是 MysteryMan 出的题,题解由失踪多年的ydc来写。
这题说白了就是求解图染色方案数,由于图染色问题是NPC的,因此只要你输出答案模6的值。
对于前
对于
对于
对于满分做法,我们首先可以推导得知答案为
所以我们唯一要做的就是考虑
我们知道,对于一个联通的二分图,确定了一个点后,其余点的颜色就都确定了。因此,我们判断整张图是否是二分图。如果不是二分图,直接输出
最后有一个小细节即
这题还有另一个思考的思路,即色数多项式——一张
排兵布阵
from MysteryMan, 题解 by jiry_2
收题的时候我感觉这题应该是 T3 的,但是当了几个月甩手掌柜之后发现这题被放到了 T2..感觉组题的人有点石乐志。
C_SUNSHINE:“行吧我石乐志……”
算法一
直接
算法二
没有移动操作,那么可以用处理矩形加,询问矩形信息的数据结构 kd-tree 来做。
时间复杂度
当然肯定有其他复杂度更低的方法。
算法三
因为这是一道对着 idea 出的题,所以不排除有简单的算法或者复杂度更低的算法,但是这题的 idea 本身还是很妙的。
考虑这么一个数据结构:我们对平面里的每一行统计这一行的点数
不难发现每一行每一列的关键点个数都是严格
于是思路就是每一个操作,都是关键点上暴力,非关键点打标记,同时对每一行每一列维护非关键点的权值最大值。这样每一次操作都是严格
只要利用好每一个点要么是行关键点,要么是列关键点,那么每一个操作都可以顺其自然的暴力了。
思路虽然简单但是细节还是比较多的:
维护权值
这个问题的核心在于把横纵的修改和询问联系起来。在刚才那个结构中,可以定义一个行关键点
这样在行操作的时候,我们把每一个行关键点的点权修改一下,同时更新这个关键点所在列的非关键点最大值。列操作类似。
关于合并
关于合并一个简单的想法是,直接把关键点集合并起来,然后把非关键点最大值取个
首先是标记,在合并两个有标记的行的时候,因为标记是不能下传的(下传要遍历每一个非关键点并修改,复杂度爆炸了)。所以标程的做法是对行和列分别维护一个并查集,同时用类似同态加边判断是否是二分图的方法,在并查集的每一条边上维护儿子和父亲的标记差。
这样对于一个原来坐标是
接着,因为在合并了两行之后,行的点数变多了,所以一些行关键点会变成列关键点。这个时候我们要遍历所有行关键点,然后看关键点是否会跑到另一边去。因为一次合并之后关键点也是
关于去重
行列的关键点个数是
去重的过程相当于把所有相同位置的关键点变成一个点,且权值为这个位置所有关键点的最大值。
如果每一次合并都去重的话,去重的复杂度在瓶颈上,必须要写 hash 之类的方法,常数较大。
实际上可以设一个阈值
因为每一次去重都至少删掉了
综上,这个算法的时间复杂度是
第三个数据集的用意是避免掉合并操作时标记合并的一些细节。当然可能存在着一些针对性的算法。
个人感觉这题的 idea 还是挺不错的,但是好的 idea 到好的题目的过程还是有点难.. 之前思考熊那题就是这么翻车的。这题虽然有
(不过 UNR 传统是 T2 最难?)
C_SUNSHINE:“Exactly!”
黎明前的巧克力
from sevenkplus, 题解 by C_SUNSHINE
题解很啰嗦,觉得想的差不多的可以直接看算法七。
算法一
我们可以
算法二
我们重新考虑算法一,我们可以先枚举一个巧克力是否在
如果我们枚举所有可能的
算法三
当
用
算法四
注意到有部分数据不同的数字种类数不算多,我们可以发现一个数字选奇数个对异或和的贡献都是一样的,于是我们用组合数预处理每个数选奇数个/偶数个的权值和,再按数字DP,每次枚举当前数字是选择奇数个还是偶数个进行转移即可,转移方法类似算法三。
假设有
算法五
继续观察算法三,可以发现每次转移相当于是原数组和当前数组
对每一个数
这样,你就可以获得…… 0 分了,可以发现这算法的复杂度是
算法六
作为新时代的OI少年,我们一定要把这个FWT优化到极致,继续观察这个FWT的性质,可以发现
可以发现每个位置都是
由于FWT是线性变换,即
接着观察可以发现,当
为什么呢?
不妨采用高维FFT理解FWT来证明一下,我们把数字
由于
那么这个式子怎么算呢?
不妨考虑枚举
现在我们会求所有元素的贡献和了,可我们要的不是贡献和啊,我们要的是贡献积,这怎么办呢?
假设对于某一个贡献和为
解出
由于要枚举集合和超集,还要做子集和变换,时间复杂度是
算法七
之前提到过,对于贡献和为
那么观察算法六我们的推导过程,可以发现我们对FWT做了细致的解析,然而既然我们知道他是FWT,其实完全可以不做这个解析,直接用FWT计算贡献和即可。
简单来说我们直接把每一个数的数组
只需要使用
算法八
这个式子,其实是可以DP计算的,令
转移时只用枚举当前位变为前
这个
不过,明眼人一下子就看出来了,这个DP其实就是一个按位分层求FWT的东西……
除此之外还有一个优化,在做逆FWT的时候,由于我们只要求
这样FWT就完全被(或者假装被)省略了……
一个用FWT推完的题代码里没有FWT也是一件有趣的事呢?
时间复杂度
Day2
积劳成疾
from MysteryMan, 题解 by C_SUNSHINE
算法
介于除了最基本的 20 分部分分,其他部分分似乎都比std难写……
于是我们直接说std做法吧!
令
那么首先对最大值是否等于
接着考虑最大值为
可以发现,所有包含位置
即
时间复杂度
梦中的题面
La tâche est écrite par ftiasch,
et la solution est écrite par matthew99
算法一
枚举前
算法二
考虑容斥,枚举有哪些数超过了限制,然后使用可重组合数算出方案数,时间复杂度为
算法三:
考虑数位DP,记录当前每一个数与限制的大小关系,然后枚举下一位的值,如果使用二进制并采用逐位逐数转移的话,时间复杂度为
算法四:
考虑
时间复杂度为
算法五:
考虑
时间复杂度为
算法六:
我们考虑从高位往低位进行数位DP,那么取0的个数最开始是
这个时候我们就不能记录进位了,我们记录从第
解开尘封的仪式
sqc太菜了,他的提答被A穿了,就当送分好了……
这种不是NPC问题的求最优解的东西果然不适合造提答……数据太难造了QAQ (出题人尽力克制数据包不太大结果出锅了QAQ)
这次提答不良心都是我的锅QAQ
下面说一下每个点的解法吧(当然还有其他做法吧):
测试点1
哇,这是一条链!我会Manacher或回文树!时间复杂度
测试点2
这个点字符全是
测试点3
这个点是由
枚举中点,暴力向两边拓展即可。
测试点4
一个比较小的一般的DAG。
考虑
测试点5
这个图是由一堆链构成的,且链以随机为主。
由于分支路径不太多,所以可以每条路径搞出来然后回文树或Manacher解决。
测试点6
这个图是一个分块图,块间有连边。
观察可以发现块间连边是一个块的某个入度为
所以这个块间连边不影响答案。
对每块用测试点4的方法做就好啦!
测试点7
哇,这是一颗树!数据范围还那么小!
这个点可以随便搞过去。
测试点8
这个点……似乎没什么特殊的性质?
那就……很尴尬了啊……
我们回头看下第7个点?
测试点7(解法2)
诶?这个字符序列……有点奇妙啊……
发现这是个由后缀组成的Trie?
找出最长链然后跑Manacher就好了吧。
测试点8
发现这个点是由一个后缀Trie+一条链+一个前缀Trie组成的。
然后就很好做了。
(泥萌怎么都会这个点啊)
测试点9
这个点是性质是一个有向的有根树。
那……试试回文树?
诶?怎么跑半天跑不出来啊,怕是不对?
现在考虑回文树为什么跑不出来。
直接回文树做的话,是均摊复杂度的。如果一条全
我们可以考虑把均摊复杂度搞成严格复杂度的。
考虑可持久化KMP的做法。
我们像可持久化KMP一样做,每个转移记录一下trans,然后就是
可以参考某篇论文。
(为了减小数据包的大小,删了一些点,这个点出锅了,被乱搞搞过去了啊)