zoukankan      html  css  js  c++  java
  • LCM Game

    链接

    第二问很简单,略过。

    第一问总的来看思维链相当长,这也就要求理解这道题时思路要相当清晰。

    拿到这道题,考虑求生成的 \(n^k\) 种序列的 LCM 和。

    考虑 LCM 的本质,事实上是对每种质因子在每个数中的出现次数取一个 \(\max\)

    以此为依据,我们可以对这 \(n\) 种数制作一个生成函数 \(f_{k}(x)\) :即 \(x^i\) 的系数为 LCM 为 i 的长度为 k 的序列的种类数。

    为了计算这个函数,我们很容易能够定义这样一种卷积: \([x^{lcm(i , j)}]f_{p + q} = [x^i]f_{p} * [x^j]f_{q}\)。(不妨称其为 \(MAX\) 卷积)

    显然 \(MAX\) 卷积的复杂度目前最快能达到 \(O(n^2)\)

    考虑去优化它。

    下面这一步很好理解,但我感觉不是很自然,有想明白内在逻辑的同学可以告诉我。

    我们可以令这两个函数在质因子分解的意义下滚一个高维前缀和,直接把相同位的系数相乘实际上就是我们得到的新函数的高维前缀和。

    把这个函数做一个高位前缀和逆变换就可以算出卷积的结果。复杂度为 \(O(n \times p)\) , 其中 \(p\) 为运算中涉及到的质数总数。

    考虑到 \(n\) 以内的 LCM 种类数有限 ,可以直接暴力做 \(k\) 次变换,听说结合第二问可以拿到 \(60pts\) 左右。

    考虑进一步优化,目前的复杂度瓶颈实际上是爆炸的 LCM 的种类数。

    考虑 LCM 的种类数多的离谱的原因。首先就要知道 LCM 种类数是怎么算的。

    容易发现,实际上是考虑每种质数的最高次数 + 1 的乘积。那么 LCM 多的原因实际上就是后面乘了一摩尔的 2。

    即,有大量的质数的最高次数都为 1 ,性质相当简单 ,但是对我们的 LCM 的总数,也即是我们的复杂度产生巨大影响,因此我们考虑统一考虑这些最高次数为 1 的质数。

    不妨去挖掘这类质数的性质。(不妨称这类质数为 A 类质数 ,不是 A 类质数的质数为 B 类质数)

    发现 B 类质数最多只有 7 个,LCM 最多只有不超过 70000 种,此时我们发现我们可以通过使用我们的 \(MAX\) 卷积解决不含 A 类质数的问题。

    由于我们解决了只含 B 类质数的子问题,我们考虑将含 A 类质数的子问题化归为只含 B 类质数的子问题。

    容易发现,在 \(n\) 以内的数不会同时包含两个 A 类的质数,因此考虑通过除去每个元素中的 A 类质数。

    注意到我们需要考虑最后的 LCM 中对于 A 类质数的存在性,因此考虑对含每个 A 类质数的数单独考虑。

    对于每一个 A 类质数 \(p\) , 我们得到含有它的数为 \(p , 2p , 3p \dots sp\) , 注意到 \(s\)\(\sqrt{n}\) 级别,所以 LCM 种类数不超过 960。

    那么我们考虑必选或必不选这些数的一些,则已知 \(p\) 的存在性 , 对于剩下的 \(1 , 2 , 3 \dots s\) 这些数做我们的 \(MAX\) 卷积 , 乘上这个质数 \(p\) 的贡献过后与总答案再做一遍背包合并答案即可(合并过程其实也是 \(MAX\) 卷积)。

    我们同样发现对只含 B 类质数的数的结果合并答案与含 A 类质数的数之间的答案合并类似,同样是做背包合并。

    注意再做背包合并的时候要考虑元素顺序,因此要乘上一个二项式系数。

    注意到在对每个质数分别考虑的时候都是对一串前缀数做 \(MAX\) 卷积,因此可以预处理。

    分析复杂度,发现复杂度瓶颈在于 A 类质数种类数远高于我们需要处理的前缀总数,预处理结果被反复高开销地调用。

    因此考虑在做预处理的时候将所有会用到该结果的质数全部完成贡献。

    事实上,我们做 \(MAX\) 卷积的本质是对每一位上的数进行枚举,我们将一个前缀作为值域进行了序列生成,现在我们为了得知哪些 A 类质数存在以计算我们接下来需要乘上的贡献,要将这些数还原回没有除去 A 类质数时的样子。

    不妨枚举有 \(j\) 个不同的 A 类质数存在,因此先乘上一个 \(h_{i,j}\) 的系数,然后考虑乘上质数贡献的系数 \(C_{i,j}\)

    无论是 \(h\) 还是 \(C\) 都相当好推到和预处理。为了方便大家,这里还是给出 \(h\)\(C\) 的定义:

    \(h_{i,j}\) 表示将生成长度为 \(i\) 元素值域为 \([1,j]\) 的序列,每个元素都出现的方案数,显然可以容斥计算。

    \(C_{i,j}\) 表示对于所有的 A 类质数中,其对应的 \(s = i\) 的部分,任意选择 \(j\) 个的乘积的和,容易递推计算。

    最后,为了方便大家的实现,这里给出算法复杂度:

    \(O(\sqrt{n} \times k^2 \times sm + k \times m \times |B|)\) ,其中 \(sm = 960\) , \(m \le 7 \times 10^4\) , |B| 为 \(B\) 类质数的个数。

    代码

  • 相关阅读:
    P6329 【模板】点分树 | 震波
    Luogu P3350 [ZJOI2016]旅行者
    Luogu [ZJOI2015]幻想乡战略游戏
    斐波那契数列简单性质
    Luogu P2056 [ZJOI2007]捉迷藏
    Luogu P4127 [AHOI2009]同类分布
    A funny story in regard to a linux newbie
    Inside the c++ object module 阅读摘要
    java并发编程
    JVM执行引擎总结(读《深入理解JVM》) 早期编译优化 DCE for java
  • 原文地址:https://www.cnblogs.com/Reanap/p/15724593.html
Copyright © 2011-2022 走看看