拓展中国剩余定理 EXCRT模板 and 拓展卢卡斯定理 EXLUCAS模板

EXCRT

学习地址:C20182030太强了
博客里面的证明很易懂。
博客里面数论的各个Part都值得一看。

比较简洁的写法:
扩展中国剩余定理:
模数不一定互质,将方程依次合并:
{ x ≡ a   (   m o d     b ) x ≡ c   (   m o d     d ) \begin{cases}x\equiv a~(\bmod~b)\\x\equiv c~(\bmod~d)\end{cases} {xa (mod b)xc (mod d)
可知 b ⋅ t + a ≡ c   (   m o d     d ) b\cdot t+a\equiv c~(\bmod~d) bt+ac (mod d)
exgcd \text{exgcd} exgcd求出 t ≡ c − a ( b , d ) ∗ ( b ( b , d ) ) − 1   (   m o d     d ( b , d ) ) t\equiv \frac {c-a}{(b,d)}*(\frac b{(b,d)})^{-1}~(\bmod~\frac {d}{(b,d)}) t(b,d)ca((b,d)b)1 (mod (b,d)d)
代回得 x ≡ b ⋅ t + a   (   m o d     [ b , d ] ) x\equiv b\cdot t+a~(\bmod~[b,d]) xbt+a (mod [b,d])
易验证 x x x满足原方程,且方程的通解为 x + k [ b , d ] x+k[b,d] x+k[b,d]

Code(洛谷P4777):

#include<bits/stdc++.h>
#define maxn 100005
#define LL long long
using namespace std;
inline LL mul(LL a,LL b,LL p){return (a*b-(LL)((long double)a*b/p)*p+p)%p;}
LL gcd(LL a,LL b){return b?gcd(b,a%b):a;}
void exgcd(LL a,LL b,LL &x,LL &y){
	if(!b) x=1,y=0;
	else exgcd(b,a%b,y,x),y-=a/b*x;
}
int main()
{
	int n; LL A1,P1,A2,P2,x,y,d,lcm;
	scanf("%d%lld%lld",&n,&P1,&A1);
	while(--n){
		scanf("%lld%lld",&P2,&A2),d=gcd(P1,P2);
		exgcd(P1/d,P2/d,x,y),lcm=P1/d*P2;
		A1=(mul(mul((A2-A1)/d,x,lcm),P1,lcm)+A1)%lcm;
		P1=lcm;
	}
	printf("%lld\n",(A1+P1)%P1);
}

EXLUCAS

学习地址:讲的很清楚

求组合数 n ! m ! ( n − m ) ! n!\over m!(n-m)! m!(nm)!n! p k p^k pk
首先求出上下除去 p p p的因子后模 p k p^k pk的值,然后求出下面模 p k p^k pk的逆元。

于是问题就是怎么求 n ! n! n!除去 p p p的因子后模 p k p^k pk的值。

首先除去 n ! n! n! p p p的倍数,那么被除的数形成了 ( n p ) ! (\frac np)! (pn)!,递归计算。剩下的数不包含 p p p的因子,形成了 [ 1 , p k ) [1,p^k) [1,pk)内不包含 p p p的因子的这一段的 n p k \frac n{p^k} pkn次重复,暴力把 [ 1 , p k ) [1,p^k) [1,pk)以内乘起来然后快速幂,剩下的非整段的长度 < p k <p^k <pk,同样暴力乘起来。
预处理 p k p^k pk以内不含 p p p因子的数的前缀积,每次递归就只需要一次快速幂了,总复杂度就是 O ( p k + log ⁡ n ) O(p^k+\log n) O(pk+logn)

但是有时候我们会遇到 p k p^k pk n n n很大,但 m m m较小的情况,这时候可以把组合数表示为 n m ‾ m ! n^{\underline m}\over m! m!nm,直接 f o r for for循环除去 p p p的因子,然后剩下的求逆元模就好了。这样复杂度是 O ( m log ⁡ m ) O(m\log m) O(mlogm)的。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值