zoukankan      html  css  js  c++  java
  • luoguP6028算术 题解(推柿子+整除分块+调和级数)

    题目
    大意很好理解,给你一个肥常奇怪的柿子,求它的值。
    30分做法(暴力):
    显然通过题目给出的柿子本身就可以(O(n))(f[i])然后再(O(n))求和,可以得到一个(O(n^2))的算法。
    60分做法(大力推柿子):
    通过一番鬼斧神工般的操作,成功把原柿子转化成(sumlimits_{dmid n}^{dleq n}frac{1}{d})
    转化过程如下:(正着推需要极其高超敏锐的数学直觉,所以我们倒着推)
    最难的一步:(sumlimits_{dmid n}frac{1}{d}=prodlimits_{i=1}^{pcnt}(frac{1}{p_i^0}+frac{1}{p_i^1}+frac{1}{p_i^2}+……+frac{1}{p_i^{cnt_i}}))
    这里的(pcnt)表示(n)所分解成的质因数的个数,(p_i)表示第i个质数,(cnt_i)表示第i个质数在n中有几个。
    正确性:每一个约数一定都是n的质因子中选某些质因子的某些次方拼成的,满足一一对应,等式前面的是所有约数和,等式后面是所有质因子所有次方的可能组合方式的和(根据乘法分配率)。
    接着往下推吧:
    (prodlimits_{i=1}^{pcnt}(frac{1}{p_i^0}+frac{1}{p_i^1}+frac{1}{p_i^2}+……+frac{1}{p_i^{cnt_i}})=prodlimits_{i=1}^{pcnt}frac{p_i^0*(1-frac{1}{p_i^{cnt_i+1}})}{1-frac{1}{p_i}})
    这一步是等比数列求和公式。
    下面:
    (prodlimits_{i=1}^{pcnt}frac{p_i^0*(1-frac{1}{p_i^{cnt_i+1}})}{1-frac{1}{p_i}}=prodlimits_{i=1}^{pcnt}frac{frac{p_i^{cnt_i+1}-1}{p_i^{cnt_i+1}}}{frac{p_i-1}{p_i}})
    (prodlimits_{i=1}^{pcnt}frac{frac{p_i^{cnt_i+1}-1}{p_i^{cnt_i+1}}}{frac{p_i-1}{p_i}}=prodlimits_{i=1}^{pcnt}frac{p^{cnt_i+1}-1}{p^{cnt_i}*(p_i-1)}=prodlimits_{i=1}^{pcnt}frac{p^{cnt_i+1}-1}{p^{cnt_i+1}-p^{cnt_i}})
    到这里,就是题目中给的柿子了,推完了……吗?
    发现这个柿子还是没有优化到(O(n))(对于每一个(n)需要枚举它的所有约数,这是(O(nsqrt n))的),还需要进一步优化
    (sumlimits_{i=1}^nsumlimits_{dmid i}frac{1}{d}=sumlimits_{d=1}^nsumlimits_{dmid i}^{ileq n}frac{1}{d})
    这一步我也不太会证,大概就是从实际意义上去考虑,枚举每一个(i),算一遍能整除它的(d),和枚举每一个(d),算一遍它能整除的(i),这样每一对(d~i)被计算的次数都是一样的,所以正确性应该没啥问题……
    然后就是最后一步辣:
    (sumlimits_{d=1}^nsumlimits_{dmid i}^{ileq n}frac{1}{d}=sumlimits_{d=1}^nlfloorfrac{n}{d} floor*frac{1}{d})
    刚才那个柿子的第二个(sum)显然就是找1~n里面有几个能被d整除的数,这个数量就是(lfloorfrac{n}{d} floor)
    至于证明(我自己口胡的):(lfloorfrac{n}{d} floor)这个柿子的结果等于在(n)以内能被(d)整除的最大的数除以(d)的结果,就是(n)以内能被(d)整除的数的个数
    这就是(O(n))的了,直接跑一遍就OK
    100分做法:(整除分块+调和级数)
    考虑继续优化这个柿子:(sumlimits_{d=1}^nlfloorfrac{n}{d} floor*frac{1}{d})
    把这个柿子拆成两半考虑:
    (sumlimits_{d=1}^nlfloorfrac{n}{d} floor*frac{1}{d}=sumlimits_{d=1}^nlfloorfrac{n}{d} floor*sumlimits_{d=1}^nfrac{1}{d})
    然后就显然发现前一半是整除分块,后一半是调和级数
    恶补下这两个知识点:

    1. 整除分块:
      要求形如(sumlimits_{d=1}^nlfloorfrac{n}{d} floor)的柿子可以(O(sqrt n))求。
      运用了在(n)以内,(n)除以很多数结果是一样的可以直接合并起来算,然后这些合并后的数大概级别是(sqrt n)的,把每一堆结果相同的(d)归为「一块」,只算一遍。
      具体操作:
      根据定义对于每一个块的起点(l)和终点(r),有(lfloorfrac{n}{l} floor=lfloorfrac{n}{r} floor),而(r)作为这一块的最后一项,有性质(lfloorfrac{n}{lfloorfrac{n}{r} floor} floor=r),所以从左到右遍历时候,对于每一个(l),直接计算((r-l+1)*lfloorfrac{n}{l} floor)然后把(l)跳到(r+1),进到下一个块,就完了。
    2. 调和级数:
      调和级数是形如(1+frac{1}{2}+frac{1}{3}+frac{1}{4}+……)的一个发散的无穷级数。
      上面的柿子中后一半(sumlimits_{d=1}^nfrac{1}{d})就是个调和级数的前n项。
      关于调和级数有这样一个柿子:(1+1/2+1/3+1/4+...1/n = ln(n+1) + r)(r)是欧拉常数约等于0.5772156649(这个柿子是欧拉推的,不是我)
      因为欧拉常数是个近似值,它会卡精度,所以我们可以预处理前(1e7)个答案的前缀和,剩下的用这个柿子求。

    所以最后的答案是:(sumlimits_{d=1}^nlfloorfrac{n}{d} floor*frac{1}{d}=sumlimits_{每一个块的l,r}(r-l+1)*lfloorfrac{n}{l} floor*(frac{1}{l}*frac{1}{l+1}*frac{1}{l+2}*……*frac{1}{r}))
    对于每一个块,计算((r-l+1)*lfloorfrac{n}{l} floor*(sum[r]/sum[l-1]))的值,然后累加起来就是答案了。
    ps:
    通过这道题我昨天花了好长时间发现一个没啥用的小规律:
    (frac{sumlimits_{dmid n} d}{n}=sumlimits_{dmid n}frac{1}{d})
    确实是对的可以证。
    我是在看了题解后尝试把原柿子正着推回去的时候,经过另一个等比数列求和((1+p_i+p_i^2+p_i^3+……)的和),变成了(frac{sumlimits_{dmid n} d}{n}),我发现自己推柿子的过程没问题,所以猜测这俩柿子是相等的,然后发现真是相等的。

  • 相关阅读:
    Android_Studio常用插件
    Android_Studio 及SDK下载
    Ubuntu 16.04 LTS 正式发布:系统将持续更新5年
    Windows通用应用平台
    Jquery局部打印插件
    WEB打印插件Lodop
    WEB打印插件jatoolsPrinter
    hdu1863
    PromiseKit入门
    高速排序
  • 原文地址:https://www.cnblogs.com/liu-yi-tong/p/13904334.html
Copyright © 2011-2022 走看看