「清华集训 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\)较小的情况下,实际运行总能有更好的表现

posted @ 2020-06-18 17:28  chasedeath  阅读(418)  评论(0编辑  收藏  举报