OI模板 gcd/逆元/同余

本文详细介绍了在OI(在线算法竞赛)中常用的gcd(最大公约数)、逆元和同余概念。讲解了如何求解ax+by=1的特解和通解,阐述裴蜀定理,讨论有理数取余问题,以及如何利用费马小定理和exgcd求解逆元。还探讨了线性递推和线性阶乘逆元的计算方法。
摘要由CSDN通过智能技术生成

OI模板 gcd/逆元/同余

Always remember long long!

gcd

inline int gcd(int a, int b){ return (b ? gcd(b, a%b) : a); }

exgcd

求解 a x + b y = 1 ax + by = 1 ax+by=1 的可行解。

inline void exgcd(int &x, int &y, int a, int b){
	if(!b){ x = 1, y = 0; return; }
	exgcd(x, y, b, a%b);
	int z = x; x = y; y = z - a / b * y;
}

a x ≡ 1 (   m o d     b ) ax\equiv 1(\bmod~b) ax1(mod b)

对于 a x ≡ 1 (   m o d     b ) ax\equiv1(\bmod~b) ax1(mod b) 的形式,可以转化为 a x + b y = 1 ax+by=1 ax+by=1 进行求解,解出特解 x 0 x_0 x0,通解即为 x 0 + k b x_0+kb x0+kb,最小正整数解 x m i n Z + = ( x 0   m o d   b + b ) m o d    b x_{min\Bbb{Z^+}}=(x_0\bmod b+b)\mod b xminZ+=(x0modb+b)modb(其实是真正通解的简化版)。

有正整数解时的一些特殊解

有整数解时的一些特殊解

整合

裴蜀定理

a x + b y = c ax+by=c ax+by=c x , y x,y x,y 为正整数)成立的充要条件是 g c d ( a , b ) ∣ c gcd(a,b)|c gcd(a,b)c显然

有理数取余

求解 x ≡ a b   (   m o d     p ) x \equiv \displaystyle\frac ab~(\bmod~p) xba (mod p)

  • 两边同乘 b b b b x ≡ a   (   m o d     p ) bx \equiv a~(\bmod~p) bxa (mod p)
  • exgcd \texttt{exgcd} exgcd 求得一 x 1 x_1 x1 使得 b x 1 ≡ 1   (   m o d     p ) bx_1 \equiv 1~(\bmod~p) bx11 (mod p)
  • 所以 b × ( a x 1 ) ≡ a   (   m o d     p ) b\times(ax_1) \equiv a~(\bmod~p) b×(ax1)a (mod p)
  • 此时 a x 1   m o d   p ax_1 \bmod p ax1modp 即为答案。
  • (当 b   m o d   p = 0 b \bmod p = 0 bmodp=0 时无解)
int getmod(int a, int b, int p){//要满足 a < p, b < p(不满足取mod)
	if(b % p == 0) return -1;
	int x, y; exgcd(x, y, b, p);
	long long ans = a * (long long)((x + p) % p) % p;
	return (int)ans;
}

逆元

费马小定理

a x ≡ 1   (   m o d     p ) ax\equiv1~(\bmod~p) ax1 (mod p) x ≡ a p − 2   (   m o d     p ) x\equiv a^{p-2}~(\bmod~p) xap2 (mod p),快速幂求解。(仅限 p p p 为质数)

exgcd

a x ≡ 1   (   m o d     p ) ax\equiv1~(\bmod~p) ax1 (mod p) 则有整数 k k k 使得 a x + p k = 1 ax+pk=1 ax+pk=1,exgcd 求解。(仅限 x ⊥ p x\perp p xp 但这个不满足的话就没有逆元了

int getinv(int x, int p){
	int a, k;
	exgcd(a, k, x, p);
	return (a % p + p) % p;
}

线性递推

初始化 1 − 1 ≡ 1 (   m o d     p ) 1^{-1}\equiv1(\bmod~p) 111(mod p)
p = k i + r p=ki+r p=ki+r k = ⌊ p i ⌋ k=\lfloor\frac pi\rfloor k=ip r = p   m o d   i r=p\bmod i r=pmodi ),则有:
k i + r ≡ 0 (   m o d     p ) k × r − 1 + i − 1 ≡ 0 (   m o d     p ) ( 两 边 同 乘 i − 1 × r − 1 ) i − 1 ≡ − k × r − 1 (   m o d     p ) i − 1 ≡ − ⌊ p i ⌋ × ( p   m o d   i ) − 1 (   m o d     p ) ( 代 入 ) i − 1 ≡ p − ⌊ p i ⌋ × ( p   m o d   i ) − 1 (   m o d     p ) \begin{aligned} ki+r&\equiv0(\bmod~p)\\ k\times r^{-1}+i^{-1}&\equiv0(\bmod~p)(两边同乘 i^{-1}\times r^{-1})\\ i^{-1}&\equiv-k\times r^{-1}(\bmod~p)\\ i^{-1}&\equiv-\lfloor\frac pi\rfloor\times (p\bmod i)^{-1}(\bmod~p)(代入)\\ i^{-1}&\equiv p-\lfloor\frac pi\rfloor\times (p\bmod i)^{-1}(\bmod~p) \end{aligned} ki+rk×r1+i1i1i1i10(mod p)0(mod p)i1×r1k×r1(mod p)ip×(pmodi)1(mod p)pip×(pmodi)1(mod p)
因为 p   m o d   i < i p\bmod i<i pmodi<i,所以 ( p   m o d   i ) − 1 (p\bmod i)^{-1} (pmodi)1 已经算过了,可以递推。

const int N = 1e7 + 10;
int inv[N];
inline void getinv(int n, int p){
	inv[1] = 1;
	for(int i = 2; i <= n; ++ i)
		inv[i] = p - (long long)p / i * inv[p%i] % p;
		//inv[i] = (long long)(p - p / i) * inv[p%i] % p; 其实都行
	return;
}

线性阶乘逆元

i n v [ ( i − 1 ) ! ] = 1 ( i − 1 ) ! = i ∗ 1 i ! = i ∗ i n v [ i ! ] inv[(i-1)!]=\displaystyle\frac{1}{(i-1)!}=i*\frac{1}{i!}=i*inv[i!] inv[(i1)!]=(i1)!1=ii!1=iinv[i!]
所以我们可以先算出 i n v [ n ! ] inv[n!] inv[n!],然后反向递推即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值