数论
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+nk−1pk−1+...+n1p+n0m=mkpk+mk−1pk−1+...+m1p+m0 m = m_kp^k+m_{k-1}p^{k-1}+...+m_1p+m_0 m=mkpk+mk−1pk−1+...+m1p+m0
Cnm=∏i=0kCnimi(mod p) C_n^m = \prod^k_{i = 0}C_{n_i}^{m_i}(mod\ p) Cnm=i=0∏kCnimi(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(n−1,m)+C(n−1,m−1)
- 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)\%pLucas(n,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=p1k1∗p2k2∗...∗pqkq(pip_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}⎩⎪⎪⎪⎨⎪⎪⎪⎧ans≡c1 mod p1k1ans≡c2 mod p2k2......ans≡cn 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的求法,以下给出解法:
- n!%pikin! \% p_i^{k_i}n!%piki是三部分的乘积
- 第一部分是pi⌊npi⌋p_i^{\lfloor \frac{n}{p_i} \rfloor}pi⌊pin⌋
- 第二部分是⌊npi⌋!\lfloor \frac{n}{p_i} \rfloor !⌊pin⌋!
- 第三部分是上面的数之外的其他数(不超过pikip_i^{k_i}piki)的乘积,可暴力
m!%pikim! \% p_i^{k_i}m!%piki和(n−m)!%piki(n-m)! \% p_i^{k_i}(n−m)!%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)a∗x+b∗y=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<ϕ(m)a(c mod ϕ(m))+ϕ(m),gcd(a,m)≠1,c≥ϕ(m)a^c \equiv\begin{cases}a^{c \ mod \ \phi(m)}, & gcd(a, m)=1\\ a^c, & gcd(a, m) \neq 1,c < \phi(m) \\a^{(c \ mod \ \phi(m))+\phi(m)}, & gcd(a, m) \neq 1,c \geq \phi(m) \end{cases}ac≡⎩⎪⎨⎪⎧ac 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 \ mac≡a(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(m−1)≡1 (mod m)
- a为m的倍数时,a(m−1)≡0 (mod m)a^{(m-1)} \equiv 0 \ (mod \ m)a(m−1)≡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}⎩⎪⎪⎪⎨⎪⎪⎪⎧X≡d1 mod p1X≡d2 mod p2......X≡dn 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;
}