T1 约数和
标准解法
\(n = a_1^{b_1} \times a_2^{b_2} \dots a_k^{b_k}\)
那么根据算术基本定理的推广,约数个数和约数和都是可以快速计算得到
约数和 sum
\(sum = (a_1^0 + a_1^2 + ...+ a_1^{b_1}) \times (a_2^0 + a_2^2 + ...+ a_2^{b_2}) \times ...\)
然后用等比数列求和把他们算出来即可
\((a_1^0 + a_1^2 + ...+ a_1^{b_1}) = \frac{a_1^{b_1 + 1} - 1}{a_1 - 1}\)
T2 文件查找
题意
有 \(n\) 个字符串 \(S_i\),全部由小写字母组成。
另有 \(m\) 个字符串 \(T_j\),除小写字母外,每个字符串中有且仅有一个 \(*\) 字符。
其中 \(*\) 字符能够匹配任意字符串(含空串)。
对每个字符串 \(T_j\),求有多少个字符串 \(S_i\) 能被匹配。
标准解法
警告:本题标准解法较为复杂,而前 90% 部分的解法更加简单易懂。
步骤 1
将所有 \(S\) 串正、反建出两棵「字典树」 \(\text{Trie}\)、\(\text{Trie}'\),将同一 \(S\) 的结束位置 \(end_S\)、\(end_S'\) 关联。
用 \(T\) 串 \(*\) 前的子串在 \(\text{Trie}\) 上匹配;\(*\) 后的子串的反串在 \(\text{Trie}'\) 上匹配。
若任何一匹配失败,则 \(T\) 不能与任何 \(S\) 匹配。
若均成功匹配,将在 \(\text{Trie}\)、\(\text{Trie}'\) 上得到的匹配结束位置分别记为 \(pos\)、\(pos'\)。
原问题转化为:求 \(\text{Trie}\) 中 \(pos\) 的子树中所有点的关联点在 \(\text{Trie}'\) 中 \(pos'\) 的子树中有多少个。
此问题能使用「DFS 序」解决。
步骤 2
\(\text{Trie}'\) 中 \(pos'\) 的子树在 \(\text{Trie}'\) 的 DFS 序中对应的区间为 \(\left[{dfn}_{pos'},{dfn}_{pos'}+{siz}_{pos'}\right)\)。
其中 \(dfn_{x}\) 表示 \(x\) 被 DFS 到的次序,\(siz_{x}\) 表示 \(x\) 子树的大小(节点数),这个序列使用「树状数组」维护。
当在 \(\text{Trie}\) 中 DFS 到 \(end_S\) 时,在 \(end_S'\) 对应的位置,即树状数组的 \({dfn}_{end_S'}\) 处 \(+1\)。
在 DFS 到 \(pos\) 时,首先(在包括上一段操作的所有操作之前)统计区间 \(\left[{dfn}_{pos'},{dfn}_{pos'}+{siz}_{pos'}\right)\) 的和,这部分是由不在 \(pos\) 子树中的 \(end_S\) 产生的,应在答案中减去。
之后递归 DFS \(pos\) 的子树,当 \(pos\) 的子树全部 DFS 完毕后,再次统计区间 \(\left[{dfn}_{pos'},{dfn}_{pos'}+{siz}_{pos'}\right)\) 的和,此次统计与第一次统计的差值就是 \(T\) 能够匹配的 \(S\) 串数量。
具体实现时,可以将询问用「链表」链接在对应的 \(pos\) 上。
时空复杂度
记 \(|S|=\sum length(s_i)\),\(|T|=\sum length(T_j)\)
时间复杂度:\(\mathcal{O}\left(|S|+|T|+m\log{|S|}\right)\)
空间复杂度:\(\mathcal{O}\left(|S|\right)\),常数约为 \(60\)
标准程序
代码长度:2460 详见 std
特殊性质与部分分
前 90%
「\(*\) 只出现在首或尾」,建出两棵字典树后求子树和即可。
其他部分分
出题人为各种其他奇奇怪怪的暴力提供了充足的数据梯度。
T3 吃糖
这道题的题意验题人视角也觉得比较难以理解,理解题意需要比较久的时间。
理解题意之后,判断完无解之后,发现这其实是一个有向图,每条边的转移是有概率的,问期望从起点多少步到达终止节点(终止节点可以有多个)。
用\(dp_i\)表示从\(i\)出发,期望需要多少步能够到达终止节点,那么:
\(dp_i=1+\sum_j(dp_j\times P_{i,j})\),\(j\)表示的是从状态\(i\)可以到达状态\(j\),\(P_{i,j}\)是状态\(i\)转移到状态\(j\)的概率。
直接对这个方程组做高斯消元,复杂度是炸裂的\(O((2^{11})^3≈8.5\times 10^9\)。
尽管我们可以在高斯消元的时候做一些常数优化(实际上最快的一次提交刚好是\(0.9\)s多一点),但还是难以通过。
考虑到这个转移图是一个很特殊的图,有着严格的层次:二进制下有\(k\)个\(1\)的状态,只会转移到二进制下有\(k\)或者\(k+1\)个\(1\)的状态,所以我们可以按二进制下的\(1\)从大到小,依次来做高斯消元,这样每一层的节点数只有\(2^k\)这么多,时间复杂度降为\(\sum_{i=0}^{n}(C_n^i)^3≈2\times 10^8\),实际上在消元的过程中我们可以只把第一行的其他位置消成\(0\),所以并不会达到上界。
T4 区间
显然 \(f(l,r)\) 等于 \([l,r]\) 中的数值种数。
\(a_i,l,r\) 随机的部分就是出现超过一次的数很少,答案与询问区间的差很小,在实际数据中两者的差 \(\le5\)。
考虑每次在序列尾部加入元素,求出加入每个元素后最短的子区间满足在整个序列中出现的数都在这个区间中出现过。
对于这个问题我们可以维护一个指针 \(p\),表示从 \(p\) 开始的后缀满足条件。添加元素 \(x\) 时,若 \(x\ne a_p\),则不对 \(p\) 做任何操作;否则,将 \(p\) 赋值为最小的 \(i\) 满足不存在 \(j>i\) 且 \(a_i=a_j\)。
容易证明这样维护总是正确的。
考虑原问题,令 \(pre_i\) 表示 \(a_i\) 上一次出现的位置,若不存在,则为 \(0\);\(nxt_i\) 表示 \(a_i\) 下一次出现的位置,若不存在,则为 \(n+1\)。
因为没有强制在线,所以离线。
枚举右端点 \(r\),对于每个 \(l\le r\),维护最大的 \(p_l\) 满足 \(f(p_l,r)=f(l,r)\)。
沿用在一个序列末尾添加元素的维护方式,每次将 \(r\) 右移时,若 \(pre_r\ne 0\),找出所有的 \(i\) 满足 \(p_i=pre_r\),将 \(p_i\) 赋值为最小的 \(j\) 满足 \(nxt_j>r\)。
由操作过程可得,\(p_i\) 单调不降。
可以用四元组 \((l,r,x,y)\) 表示右端点为 \(y\) 时,将 \(p_i(i\in [l,r])\) 赋值为 \(x\)。
我们对每组询问 \([u,w]\),可以用三元组 \((u,v,w)\) 描述,\(v\) 为最小的满足 \(f(l,v)=f(l,r)\) 的值。
容易发现,答案为 \(\min(v-(\min\limits_{u\le i\le v,nxt_i>v}i)+1,\min\limits_{l\le u\le r,v \le y \le w} (y-x+1))\)。
前一部分是平凡的,后一部分可以枚举 \(y\),操作转化为单点插入、单点求值、区间取 \(\min\)。
可以预处理出所有的 \(u\) 并离散化,使用线段树维护。
若 \(u\) 相同则无法正确维护,离散化时需强制两两不同。
设 \(n,m\) 同阶,时间复杂度 \(O(n\log n)\),空间复杂度 \(O(n)\)。
标签:le,Trie,题解,复杂度,2023,pos,dfn,text,CCF From: https://www.cnblogs.com/Mysterious-Cat/p/17156567.html