「清华集训 2017」小 Y 和恐怖的奴隶主
「清华集训 2017」小 Y 和恐怖的奴隶主
是不是这题太水了都没人写啊
本题官方题解提供的做法实际上复杂度非常高
Part1
很显然本题的 \(\text{dp}\) 是存储每种血量的随从数量
设状态数量的上限是 \(S\)
当 \(m=3,k=8\) 时,这样的状态一共有 \(S=165+1\) 种
如果直接 \(dp\) ,每次转移是 \(O(1)\) 的,可以做到 \(O(n\cdot S)\) ,显然无法处理 \(n\) 较大的情况
用矩阵优化 \(\text{dp}\) 转移,朴素的实现可以做到 \(O(T\cdot \log n\cdot S^3)\)
如果预处理出转移矩阵的幂次,每次查询时只有列向量与方阵的乘法,所以复杂度是 \(O(\log n\cdot S^3+T\log n\cdot S^2)\)
实际极限的复杂度预估在 \(60\cdot 166^3+500\cdot 60\cdot 166^2\approx 11\cdot 10^8\)
官方题解提供的做法就是在在这个算法上进行常数优化,这wtm
\[ \ \]
Part2
对于已知 \(m,k\) 来说,设每个 \(n\) 构成的答案数列为 \(a_n\)
预先处理一部分的答案 \(a_1\cdots a_n\) ,使用 \(\text{Berlekamp-Massey }\) 算法求出序列的最短线性递推
发现总是在 \(O(S)\) 的长度以后,递推序列不再改变,即总能得到一个长度为 \(O(S)\) 的全局线性递推
即总可以在 \(O(S^2)\) 的时间内求出答案序列 \(a_n\) 的线性递推式
那么对于求得的线性递推式,问题转化为对于每个查询的 \(n\) ,求常系数线性递推数列的第 \(n\) 项答案
用特征多项式的做法,可以做到单组查询 \(O(S\log n\log S)\) 的之间求出
那么总复杂度就是 \(O(S^2+T\cdot S \log S\log n)\)
理论上来说,复杂度上限应该只有 \(166^2+500\cdot 166\cdot 10\cdot 60\approx 0.5\cdot 10^8\)
理论上来说,这个复杂度无论是不是渐进意义下都比矩阵快
但是实际实践中,由于多项式运算的大常数,不优秀的实现下甚至可能超时
考虑到本题多查询的性质,我改变了倍增的基数 \(D\) ,并且预处理出倍增用到的 \(x^i\mod \lambda\)
预处理部分的复杂度是 \(O(\log_D^n \cdot (D-1)\cdot S\log S)\)
查询部分的复杂度是 \(O(\log _D^n S\log S)\)
由于我的多项式模板不够成熟
在LOJ上,经过这样的魔改,已经能跑得比矩阵块
但是在UOJ上,我同样的代码竟然慢了四倍,而这份代码在UOJ上的运行时间还略有提高
表示很是绝望。。
事实上,这种做法在 \(m,k\) 较大时同样可行,在 \(S\) 较大, \(T\) 较小的情况下,实际运行总能有更好的表现