数论总结

数论

1.1 Lucas定理 (扩展Lucas定理)【组合数取模】

Lucas定理:

要计算Cnm%pC_n^m \%pCnm%p的值
n=nkpk+nk−1pk−1+...+n1p+n0 n = n_kp^k+n_{k-1}p^{k-1}+...+n_1p+n_0 n=nkpk+nk1pk1+...+n1p+n0

m=mkpk+mk−1pk−1+...+m1p+m0 m = m_kp^k+m_{k-1}p^{k-1}+...+m_1p+m_0 m=mkpk+mk1pk1+...+m1p+m0

Cnm=∏i=0kCnimi(mod p) C_n^m = \prod^k_{i = 0}C_{n_i}^{m_i}(mod\ p) Cnm=i=0kCnimi(mod p)

即将n.m分解为p进制,然后求每一位上的组合数,再乘起来,就是答案

  • 1、当n,m都很小的时候可以利用杨辉三角直接求。
  • C(n,m)=C(n−1,m)+C(n−1,m−1)C(n,m)=C(n-1,m)+C(n-1,m-1)C(n,m)=C(n1,m)+C(n1,m1)
  • 2、n和m较大,但是p为素数的时候,递归求解:
  • Lucas(n,m)%p=Lucas(n/p,m/p)∗C(n%p,m%p)%pLucas(n,m) \%p = Lucas(n/p,m/p) * C(n\%p,m\%p)\%pLucasn,m)%p=Lucas(n/p,m/p)C(n%p,m%p)%p
  • 递归出口:m=0时返回1
  • p较小时,可以预处理阶乘
LL qpow(LL a, LL b, LL p)//快速幂取模
{
    LL ans = 1;
    a %= p;
    while(b)
    {
        if(b & 1)
        {
            ans = ans * a % p;
            b--;
        }
        b >>= 1;
        a = a * a % p;
    }
    return ans;
}

LL inv(LL a, LL p)//求逆元,要求p为素数,且a和m互质
{
    return qpow(a, p - 2, p);
}

LL C(LL n, LL m)//求组合数
{
    if(m > n) 
        return 0;
    LL ans = 1;
    for(int i = 1; i <= m; i++)
    {
        LL a = (n + i - m) % p;
        LL b = i % p;
        ans = ans * (a * inv(b, p) % p) % p;
    }
    return ans;
}

LL Lucas(LL n, LL m)//求组合数取模
{
    if(m == 0) return 1;
    return C(n % p, m % p) * Lucas(n / p, m / p) % p;
}

//打表预处理组合数,可以加快阶乘计算
void getfac(int p)//阶乘表
{
    fac[0] = fac[1] = 1;
    for(int i = 2 ; i <= p; i++)
        fac[i] = fac[i - 1] * i % p;
}

LL C(LL n, LL m, LL p) //组合数
{
    if(m > n)
        return 0;
    else
        return fac[n] * inv(fac[m] * fac[n - m], p) % p;
}
  • n,m较大且p不为素数的时候,扩展Lucas定理

  • p=p1k1∗p2k2∗...∗pqkqp=p_1^{k_1}*p_2^{k_2}*...*p_q^{k_q}p=p1k1p2k2...pqkqpip_ipi是质数)

  • 列出同余方程组{ans≡c1 mod p1k1ans≡c2 mod p2k2......ans≡cn mod pnkn\begin{cases} ans \equiv c_1 \ mod \ p_1^{k_1} \\ ans \equiv c_2 \ mod \ p_2^{k_2} \\...... \\ans \equiv c_n \ mod \ p_n^{k_n} \end{cases}ansc1 mod p1k1ansc2 mod p2k2......anscn mod pnkn

  • 其中ci...cqc_i...c_qci...cq是对于每一个Cnm%pikiC_n^m \% p_i^{k_i}Cnm%piki求出的答案

  • 使用中国剩余定理即可求出ans。

  • 其中Cnm%pikiC_n^m \% p_i^{k_i}Cnm%piki的求法关键在于n!%pikin! \% p_i^{k_i}n!%piki的求法,以下给出解法:

    1. n!%pikin! \% p_i^{k_i}n!%piki是三部分的乘积
    2. 第一部分是pi⌊npi⌋p_i^{\lfloor \frac{n}{p_i} \rfloor}pipin
    3. 第二部分是⌊npi⌋!\lfloor \frac{n}{p_i} \rfloor !pin!
    4. 第三部分是上面的数之外的其他数(不超过pikip_i^{k_i}piki)的乘积,可暴力
  • m!%pikim! \% p_i^{k_i}m!%piki(n−m)!%piki(n-m)! \% p_i^{k_i}(nm)!%piki的结果可能与pikip_i^{k_i}piki不互质,无法求逆元,所以要先去除其中的质因子pip_ipi,求出逆元后,再乘回去。

  • 计算n!n!n!中的质因子p的个数x:x=⌊np⌋+⌊np2⌋+...x=\lfloor \frac{n}{p} \rfloor + \lfloor \frac{n}{p^2} \rfloor+...x=pn+p2n+...

  • 递推式为:f(n)=f(⌊np⌋)+⌊np⌋f(n)=f(\lfloor \frac{n}{p} \rfloor)+\lfloor \frac{n}{p} \rfloorf(n)=f(pn)+pn

LL qpow(LL a, LL n, LL m)//快速幂
{
    LL ans = 1;
    a %= m;
    while(n)
    {
        if(n & 1)
            ans = ans * a % m;
        n >>= 1;
        a = a * a % m;
    }
    return ans;
}

//求解ax+by=gcd(a, b)
//返回值为gcd(a, b)
LL exgcd(LL a, LL b, LL& x, LL& y)//扩展欧几里得
{
    LL d = a;
    if(b)
    {
        d = exgcd(b, a % b, y, x);
        y -= (a / b) * x;
    }
    else x = 1, y = 0;
    return d;
}

//求解a关于模上m的逆元
//返回-1表示逆元不存在
LL inv(LL a, LL m)
{
    LL x, y;
    LL d = exgcd(a, m, x, y);
    return d == 1 ? (m + x % m) % m : -1;
}

//计算n! mod p^k的部分值,pk为p_i的k_i次方,算出的答案不包括pi的幂的那一部分
LL Mul(LL n, LL pi, LL pk)
{
    if(!n) return 1;
    LL ans = 1;
    if(n / pk)
    {
        for(LL i = 2; i <= pk; i++) //求出循环节乘积
            if(i % pi) ans = ans * i % pk;
        ans = qpow(ans, n / pk, pk); //循环节次数为n / pk
    }
    for(LL i = 2; i <= n % pk; i++)
        if(i % pi) ans = ans * i % pk;
    return ans * Mul(n / pi, pi, pk) % pk;//递归求解
}

LL C(LL n, LL m, LL p, LL pi, LL pk)//计算组合数C(n, m) mod p^k的值 p^k为p_i的k-i次方
{
    if(m > n) return 0;
    LL a = Mul(n, pi, pk), b = Mul(m, pi, pk), c = Mul(n - m, pi, pk);
    LL k = 0, ans;//k为pi的幂值
    for(LL i = n; i; i /= pi) k += i / pi;
    for(LL i = m; i; i /= pi) k -= i / pi;
    for(LL i = n - m; i; i /= pi) k -= i / pi;
    ans = a * inv(b, pk) % pk * inv(c, pk) % pk * qpow(pi, k, pk) % pk;//ans就是n! mod pk的值
    ans = ans * (p / pk) % p * inv(p / pk, pk) % p;//此时用剩余定理合并解
    return ans;
}

LL Lucas(LL n, LL m, LL p)//求组合数C(n, m) mod p的值,p为合数
{
    LL x = p;
    LL ans = 0;
    for(LL i = 2; i <= p; i++)
    {
        if(x % i == 0)
        {
            LL pk = 1;
            while(x % i == 0)pk *= i, x /= i;//将p分解成质数幂的乘积
            ans = (ans + C(n, m, p, i, pk)) % p;//剩余定理求解
        }
    }
    return ans;
}

1.2 扩展欧几里得

a∗x+b∗y=gcd(a,b)a*x+b*y=gcd(a, b)ax+by=gcd(a,b)的解

//求解ax+by=gcd(a, b)
//返回值为gcd(a, b)
LL exgcd(LL a, LL b, LL& x, LL& y)
{
    LL d = a;
    if(b)
    {
        d = exgcd(b, a % b, y, x);
        y -= (a / b) * x;
    }
    else x = 1, y = 0;
    return d;
}

1.3 威尔逊定理

p可以整除(p-1)!+1是p为质数的充要条件

1.4 欧拉定理(扩展欧拉定理)【高次幂:对指数取模(模无限制)】

  • 欧拉定理:

​ 若a,m为整数,且a,m互质,则aϕ(m)≡1 (mod m)a^{\phi(m)} \equiv 1\ (mod\ m)aϕ(m)1 (mod m)

  • 扩展欧拉定理:

ac≡{ac mod ϕ(m),gcd(a,m)=1ac,gcd(a,m)≠1,c&lt;ϕ(m)a(c mod ϕ(m))+ϕ(m),gcd(a,m)≠1,c≥ϕ(m)a^c \equiv\begin{cases}a^{c \ mod \ \phi(m)}, &amp; gcd(a, m)=1\\ a^c, &amp; gcd(a, m) \neq 1,c &lt; \phi(m) \\a^{(c \ mod \ \phi(m))+\phi(m)}, &amp; gcd(a, m) \neq 1,c \geq \phi(m) \end{cases}acac mod ϕ(m),ac,a(c mod ϕ(m))+ϕ(m),gcd(a,m)=1gcd(a,m)̸=1,c<ϕ(m)gcd(a,m)̸=1,cϕ(m)

  • 因此求高次幂,无论a,n是否互质,都可以使用ac≡a(c mod ϕ(m))+ϕ(m) mod ma^c \equiv a^{(c \ mod \ \phi(m))+\phi(m)} \ mod \ maca(c mod ϕ(m))+ϕ(m) mod m

1.5 费马小定理【高次幂:对指数取模(模为质数)】

​ m为质数

  • a不为m的倍数时,a(m−1)≡1 (mod m)a^{(m-1)} \equiv 1 \ (mod \ m)a(m1)1 (mod m)
  • a为m的倍数时,a(m−1)≡0 (mod m)a^{(m-1)} \equiv 0 \ (mod \ m)a(m1)0 (mod m)
  • 因此求高次幂,可以用该定理对指数取模

1.6 中国剩余定理

求线性同余方程组

{X≡d1 mod p1X≡d2 mod p2......X≡dn mod pn\begin{cases} X \equiv d_1 \ mod \ p_1 \\ X \equiv d_2 \ mod \ p_2 \\...... \\X \equiv d_n \ mod \ p_n \end{cases}Xd1 mod p1Xd2 mod p2......Xdn mod pn

求X的值

const int N = 15;
int n;
LL yu[N], mo[N];

LL exgcd(LL a, LL b, LL &x, LL &y)
{
    if(b == 0)
    {
        x = 1;
        y = 0;
        return a;
    }
    LL r = exgcd(b, a % b, x, y);
    LL tmp = y;
    y = x - (a / b) * y;
    x = tmp;
    return r;
}

LL CRT(LL *yu, LL *mo, int num)
{
    LL M = 1, ans = 0, x, y;
    for(int i = 0; i < num; i++)
        M *= mo[i];
    for(int i = 0; i < num; i++)
    {
        LL w = M / mo[i];
        exgcd(w, mo[i], x, y);
        ans = (ans + yu[i] * x * w) % M;
    }
    return (ans + M) % M;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值