A Codechef LUCKYDAY
阴间题。除开卡常和细节还是道很好的题。
,会想到寻找循环节。由于下一个数会和前两个数有关,因此循环结最大不会超过 ,也就是 级别。但是这个数是可以卡满的,而这题 显然不会放过去暴力。
如何找循环节呢,考虑这个转移写成矩乘,设转移矩阵是 ,于是问题就变成了找最小的 使得
其中 是初始的矩阵也就是
但是这里不等价于 因为 显然不满秩。
我们可以 考虑做一次矩阵 BSGS
来找到循环节。这里复杂度是 的,具体来说先把 做 Hash
存进 Hash
表,然后把 拆成 枚举 来查是否存在 这个东西。
然后再考虑如何求出一次循环节中的 出现的位置。我们考虑枚举 的上一个数 ,于是就成了寻找循环节中 这样的矩阵是否出现过,显然一个循环节中最多只会出现一次。这个我们仍然可以类似刚刚的进行矩阵 BSGS
也就是写成 的形式来做。
由于我们需要枚举 个 的上一个位置,设步长为 ,复杂度就是 ,显然 的时候最优。这样复杂度就优化到了 这样的东西。
然后这题还有特殊情况以及卡常。先说说特殊情况。
如果 ,那么转移矩阵就是
这个矩阵好像不满秩!不管怎么乘,也不一定能乘回单位矩阵,其实仔细思考一下也是,如果递推式是 ,这个递推式就和 无关了,如果后面循环显然不一定能循环回 。
但是这种情况显然循环节大小不超过 ,所以可以暴力跑。
由于还要考虑 的情况,一种比较方便的解决方式是从第三个数开始找循环节。
关于卡常。
首先这题不能用 unordered_map
之类的,还是得拉链 Hash
不然卡不过去。
然后矩阵乘法是可以优化的,由于 我们显然可以把矩阵乘法乘完了再一起模,取模次数从 变成了 。
然后我的一种卡过去的方式是,先用 来算循环节,然后用循环节的 次方来做,会快一些。
B COT4 Count On A Trie
我们考虑把所有 中的串全部反过来。
于是我们直接对题目中给的 的 trie
建立 SAM
就得到了所有 的串构造出的后缀树。同时这个东西的叶子的 dfs
序排序就是后缀排序。
然后我们考虑把所有 对应到 的 SAM
上的某个节点,于是往前加字母就是在 SAM
上走,往后加字母就是在后缀树上走。
考虑如何做拼接操作。
考虑我们要把 拼接成 作为新的一个 。考虑 在后缀树上的节点是 ,那么 所在的节点必然在 子树之内。我们考虑把子树内的叶子写成一个序列,那么 可以对应到 表示一个极大的区间使得区间的所有串的 LCP
是 。我们尝试二分一下 的左端点和右端点。比如二分左端点,我们可以二分出一个叶子位置 ,现在需要看一看 位置的字符串除开 这个前缀后得到的串和 的大小关系,这个就是在 trie
上跳 级祖先。我们需要找到小于 的最大的以及大于 最小的即可。
C OnePointNineNine
如果画一下图会发现,有很多点的所有邻居都是相同的。我们可以把这些点缩起来。然后可以证明的是,如果把距离不到 的点连起来,得到的东西所有点度数不超过 。
首先可以发现,对于任意两点 如果它们的距离不超过 ,那么一定会被缩起来。因为考虑如果有一点 满足 ,显然 ,不可能成立。所以对于任意两点 如果有边,那么一定有 。然后讨论一下 根据PPT有 当距离不超过 都是对的。
于是直接对换和链分别做 即可。