zoukankan      html  css  js  c++  java
  • 快速阶乘算法(暂无实践)

    Problem

    模板题luogu5282

    • n! mod pn! mod ppp是质数
    • 由于是任意模数,所以需要MTT。

    nlog2nsqrt{n}log^2n

    • 一种暴力 的方法是多项式加分块,设定一个块的大小BB,以及这样一个多项式:
      f(x)=i=1B(x+i)f(x)=prod_{i=1}^B{(x+i)}
    • 那么答案就是f(0)f(B)f(2B)...f(n/BB)Bf(0)*f(B)*f(2B)*...*f(n/B*B)*最后剩下不超过B的部分的乘积
    • 直接利用多项式多点求值可以搞到nlog2nsqrt{n}log^2n的复杂度。

    nlognsqrt{n}logn

    • 直接求系数实在是太慢了,我们可以考虑另一种多项式的优秀处理方法——点值。
    • fd(x)=i=1d(x+i)f_d(x)=prod_{i=1}^d(x+i),那么我们最后就是要求所有的fB(iB)f_B(iB)
    • 利用倍增的思路,如果我们可以做到从fd(0,B..dB)f_d(0,B..dB)f2d(0,B..2dB)f_{2d}(0,B..2dB)的乘二的转化,以及加一的转化,那么就可以倍增求出最后的BB个点值了

    乘二

    • 对于fd(0,B...dB)f_d(0,B...dB),首先需要变成fd(0,B...2dB)f_d(0,B...2dB).
    • 然后再在对应位置上乘上fd(d,d+B...,d+2dB)f_d(d,d+B...,d+2dB),就可以变成f2d(0,B...2dB)f_{2d}(0,B...2dB)
    • 考虑第一步需要得到fd(dB...2dB)f_d(dB...2dB),再综合第二步,都相当于是从fd(iB)f_d(iB)变成fd(iB+x)f_d(iB+x)
    • 系统化得来说,假设h(i)=fd(iB)h(i)=f_d(iB),那么相当于我们已知h(0..d)h(0..d),要求h(0+x/B,1+x/B..d+x/B)h(0+x/B,1+x/B..d+x/B)
    • 运用拉格朗日插值:
      h(Δ+n)=i=0dh(i)jiΔ+njijh(Delta +n)=sum_{i=0}^dh(i)prod_{j eq i}frac{Delta+n-j}{i-j}
      =j=0d(Δ+nj)i=0dh(i)(1)nii!(ni)!1Δ+ni=prod_{j=0}^d(Delta+n-j)sum_{i=0}^dfrac{h(i)*(-1)^{n-i}}{i!(n-i)!}*frac{1}{Delta+n-i}
    • 由于d<=Bd<=B,所以不会出现Δ+nj=iDelta+n-j=i的情况。后面可以直接FFT,前面的只需要用双指针扫一遍即可。

    加一

    • fd(0,B..dB)f_d(0,B..dB)fd+1(0,B..dB,(d+1)B)f_{d+1}(0,B..dB,(d+1)B)直接暴力即可。

    时间复杂度

    • T(n)=T(n/2)+n log n=T(n log n)T(n)=T(n/2)+n log n=T(n log n)
  • 相关阅读:
    【Unity3D】3D游戏学习
    风投小观之敢于冒高风险,方能收高回报
    同步请求和异步请求的区别
    IOS开发UI基础学习-------总结
    我的哲学观-1000字例文
    Uva11292--------------(The Dragon of Loowater)勇者斗恶龙 (排序后贪心)
    学习笔记之vector向量容器
    欧几里得算法求最大公约数+最小公倍数
    二叉树的遍历规则(前序遍历、后序遍历、中序遍历)
    《winform窗体应用程序》----------简易记事本
  • 原文地址:https://www.cnblogs.com/DeepThinking/p/13090886.html
Copyright © 2011-2022 走看看