• 组合数取模


    明确一下,我们要求这个:

    [{n choose m} mod t ]

    defs

    假设(n,m,t le 2^w),(w)是字长,即认为+-×÷全是basic operation((O(1))).

    [{n choose m} = frac{n^{underline{m}}}{m!} = frac{n}{(m-n)!m!} ]

    [R_p(x)$$为$x$的质因数分解中质因数$p$的次数,若$p$不是质数则$R_p(x)=0$.可以在$O(log_p{n})$的时间复杂度内求出. $$primes = mathtt{Set~of~primes.}]

    [pr(x) = [x in primes] ]

    algos

    (pr(t)~~t,n,m le 10^9)

    预处理阶乘与阶乘逆元.

    (pr(t)~~tle 10^9, n,mle 10^{18})

    Lucas定理.

    ({n choose m}equiv {lfloor n/t floor choose lfloor m/t floor} {n mod t choose m mod t} pmod{t})

    (O(n),O(log{n}))

    Chinese remainder theorem(CRT)

    解方程组(mathtt{Constraint:~}forall i ot= j,gcd{i,j}=1,mathtt{Equations:~}forall i,xequiv y_ipmod{t_i})

    (有点显然,但是需要证明)(xequiv sum_i y_i b_i frac{prod_j t_j}{t_i} pmod{prod_j t_j}),其中(b_i=left(left( prod_j t_j ight) / t_i ight)^{-1} mod t_i),大概考虑下贡献什么的就能理解它的正确性.

    (pr(t)~~tle 10^{10}, n,mle 10^{18})

    前置技能FFT mod any prime,多项式多点求值.(而且数据范围略鬼畜,好自为之吧(如果你要去写的话= =))

    考虑如何求出阶乘,构造多项式(f_n(x)=prod_{i=1}^n(x+i)),显然(n!=f_n(0)).我们考虑如何计算.那么我们考虑(f_n(0)=prod_{i=0}^mf_m(im))(其中(n)=(m^2)),如果不是(n)完全平方数只会剩下(O(sqrt{n}))项,暴力做,不然就先把这个式子求出来,多点求值一下.复杂度是(O(sqrt{n}log^2{n})),当然做(n,mle 10^{18})就顺手Lucas一发(求两次).如果你有工业级的工具可以去试试.

    (t=p^q, pr(p))

    (q=1)用上面的算法,否则(p)不太大.

    首先用(R)函数处理掉答案的(p)因子,现在问题是求(f_nmod{p^q}).我们发现这时的(f_n)最高次项最多是(q-1)次(显然).考虑倍增(f_n).

    (f_{2px+d}=f_{px}f_{px}(px)f_d(2px)).其中(dle p),那么复杂度是(O(q^2))倍增一次,总共(O(log{n}))次,加上预处理(f_d)总复杂度(O(q^2log{n}+pq)).

    这里计算都是纯暴力计算.大约可以优化一下但是因为p不会很大应该也只有优化(f_d)的计算会有些实际意义.

    没有性质的题目

    CRT+上面的算法+一些优化.

    常数优化

    然而我们的(f_n)函数可以直接求下降幂,常数/1.5 get.

    为什么(O(n))能跑(10^9)

    假设是题答/PE环境.

  • 相关阅读:
    10.2 查找同一组或分区中行之间的差
    8.7 确定当前记录和下一条记录之间相差的天数
    8.6 计算一年中周内各日期的次数
    8.5 确定两个日期之间的秒、分、小时数
    8.4 确定两个日期之间的月份数或年数
    8.2 计算两个日期之间的天数
    8.3 确定两个日期之间的工作日数目
    8.1 加减日、月、年
    7.13 计算不包含最大值和最小值的均值
    第3章 Python的数据类型 第3.1节 功能强大的 Python序列概述
  • 原文地址:https://www.cnblogs.com/tmzbot/p/5675004.html
Copyright © 2020-2023  润新知