§ 欧几里得算法
基本知识
最大公约数、最小公倍数
用 gcd(a,b)
表示 a a 和 b b 的最大公约数
用 lcm(a,b)
表示 a a 和 b b 的最小公倍数
定理
lcm(a,b)=(a*b)/gcd(a,b)
最大公约数的相关性质
gcd ( a , b ) = gcd ( b , a ) gcd ( a , b ) = gcd ( b , a )
gcd ( a , b ) = gcd ( − a , b ) gcd ( a , b ) = gcd ( − a , b )
gcd ( a , b ) = gcd ( b , a − b ) gcd ( a , b ) = gcd ( b , a − b )
gcd ( a , b ) = gcd ( b , a % b ) gcd ( a , b ) = gcd ( b , a % b )
gcd ( a , 0 ) = | a | gcd ( a , 0 ) = | a |
gcd ( a , k a ) = | a | gcd ( a , k a ) = | a |
gcd ( m a , m b ) = m × gcd ( a , b ) gcd ( m a , m b ) = m × gcd ( a , b )
gcd ( a , b ) = gcd ( a + m b , b ) gcd ( a , b ) = gcd ( a + m b , b )
gcd ( a b , m ) = gcd ( a , m ) × gcd ( b , m ) gcd ( a b , m ) = gcd ( a , m ) × gcd ( b , m )
gcd ( a , p ) = 1 , gcd ( b , p ) = 1 ⇒ gcd ( a × b , p ) = 1 gcd ( a , p ) = 1 , gcd ( b , p ) = 1 ⇒ gcd ( a × b , p ) = 1
更相减损法(略)
Euclidean Algorithm
定义及原理
又称 辗转相除法
原理 gcd ( a , b ) = gcd ( b , a % b ) gcd ( a , b ) = gcd ( b , a % b )
用法
template <class T >inline T gcd (T a,T b) {
return b==0 ?a:gcd (b,a%b);
}
证明
设 d = gcd ( a , b ) , d ∈ Z + 有 a = m d , b = n d , 其 中 m , n ∈ Z + , 且 gcd ( m , n ) = 1 令 r = a % b ⇒ r = a − q b = m d − q n d = d ( m − q n ) , ( q ∈ Z + ) ∵ gcd ( b , r ) = gcd ( n d , d ( m − q n ) ) = d × gcd ( n , m − q n ) = gcd ( a , b ) × gcd ( n , m − q n ) 且 gcd ( n , m ) = 1 ⇒ gcd ( n , m − q n ) = 1 ∴ gcd ( a , b ) = gcd ( b , a % b ) = d 得 证 设 d = gcd ( a , b ) , d ∈ Z + 有 a = m d , b = n d , 其 中 m , n ∈ Z + , 且 gcd ( m , n ) = 1 令 r = a % b ⇒ r = a − q b = m d − q n d = d ( m − q n ) , ( q ∈ Z + ) ∵ gcd ( b , r ) = gcd ( n d , d ( m − q n ) ) = d × gcd ( n , m − q n ) = gcd ( a , b ) × gcd ( n , m − q n ) 且 gcd ( n , m ) = 1 ⇒ gcd ( n , m − q n ) = 1 ∴ gcd ( a , b ) = gcd ( b , a % b ) = d 得 证
裴蜀定理
定义及原理
又名贝祖定理
∀ a , b ∈ Z + , 且 gcd ( a , b ) = d 关 于 x , y 的 线 性 不 定 方 程 : a x + b y = c 有 整 数 解 ( x , y ) , 当 且 仅 当 c % d = 0 特 别 地 , 一 定 存 在 x , y ∈ Z , 使 得 a x + b y = d 成 立 ∀ a , b ∈ Z + , 且 gcd ( a , b ) = d 关 于 x , y 的 线 性 不 定 方 程 : a x + b y = c 有 整 数 解 ( x , y ) , 当 且 仅 当 c % d = 0 特 别 地 , 一 定 存 在 x , y ∈ Z , 使 得 a x + b y = d 成 立
证明
设 d = gcd ( a , b ) 设 s 是 满 足 等 式 a x + b y = s , x , y ∈ Z 的 最 小 正 数 设 r = a % s ⇒ r = a − q s , 其 中 q ∈ Z 令 x ′ = 1 − q x , y ′ = − q y 有 r = a x ′ + b y ′ ∵ 0 ≤ r < s 且 s 是 满 足 等 式 a x + b y = s , x , y ∈ Z 的 最 小 正 数 ⇒ r = 0 ∴ a % s = 0 同 理 b % s = 0 ∴ s 是 a , b 的 一 个 公 约 数 ∴ d = k s , k ∈ Z + ∵ 不 定 方 程 a x + b y = s 有 整 数 解 ( x , y ) ∴ 不 定 方 程 一 定 有 整 数 解 ( k x , k y ) 得 证 设 d = gcd ( a , b ) 设 s 是 满 足 等 式 a x + b y = s , x , y ∈ Z 的 最 小 正 数 设 r = a % s ⇒ r = a − q s , 其 中 q ∈ Z 令 x ′ = 1 − q x , y ′ = − q y 有 r = a x ′ + b y ′ ∵ 0 ≤ r < s 且 s 是 满 足 等 式 a x + b y = s , x , y ∈ Z 的 最 小 正 数 ⇒ r = 0 ∴ a % s = 0 同 理 b % s = 0 ∴ s 是 a , b 的 一 个 公 约 数 ∴ d = k s , k ∈ Z + ∵ 不 定 方 程 a x + b y = s 有 整 数 解 ( x , y ) ∴ 不 定 方 程 一 定 有 整 数 解 ( k x , k y ) 得 证
扩展欧几里得
定义
已知 a , b a , b ,扩展欧几里得算法可以求出 gcd ( a , b ) , 以 及 x , y ∈ Z gcd ( a , b ) , 以 及 x , y ∈ Z ,满足 a x + b y = gcd ( a , b ) a x + b y = gcd ( a , b )
用法
template <class T >inline T exgcd (T a,T b,T&x,T&y) {
if (b==0 ){
x=1 ,y=0 ;return a;
}
T gcd=exgcd (b,a%b,y,x);
y=y-a/b*x;
return gcd;
}
解释
i ) b = 0 时 gcd ( a , b ) = a 方 程 可 化 为 a × x + 0 × y = a ∴ x = 1 , y = 0 是 这 个 方 程 的 一 组 解 ii ) b > 0 时 ∵ gcd ( a , b ) = gcd ( b , a % b ) ∴ 可 以 列 出 以 下 等 式 a x 1 + b y 1 = gcd ( a , b ) b x 2 + ( a % b ) y 2 = gcd ( b , a % b ) ∵ a % b = a − b ⌊ a b ⌋ 且 gcd ( a , b ) = gcd ( b , a % b ) ∴ a x 1 + b y 1 = b x 2 + ( a − b ⌊ a b ⌋ ) y 2 = a y 2 + b ( x 2 − y 2 ⌊ a b ⌋ ) ∴ x 1 = y 2 , y 1 = x 2 − y 2 ⌊ a b ⌋ (1) (2) i ) b = 0 时 gcd ( a , b ) = a 方 程 可 化 为 a × x + 0 × y = a ∴ x = 1 , y = 0 是 这 个 方 程 的 一 组 解 ii ) b > 0 时 ∵ gcd ( a , b ) = gcd ( b , a % b ) ∴ 可 以 列 出 以 下 等 式 (1) a x 1 + b y 1 = gcd ( a , b ) (2) b x 2 + ( a % b ) y 2 = gcd ( b , a % b ) ∵ a % b = a − b ⌊ a b ⌋ 且 gcd ( a , b ) = gcd ( b , a % b ) ∴ a x 1 + b y 1 = b x 2 + ( a − b ⌊ a b ⌋ ) y 2 = a y 2 + b ( x 2 − y 2 ⌊ a b ⌋ ) ∴ x 1 = y 2 , y 1 = x 2 − y 2 ⌊ a b ⌋
由上面的推导可以知道:
当递归达到边界条件时 (b==0)
,x = 1 , y = 0 x = 1 , y = 0 是目标方程的一组解 ( x 2 , y 2 ) ( x 2 , y 2 )
在向上返回的过程中,对应方程的解也会发生改变
若上一层返回的解为 ( x 2 , y 2 ) ( x 2 , y 2 ) ,则本层对应的解为 ( y 2 , x 2 − y 2 ⌊ a b ⌋ ) ( y 2 , x 2 − y 2 ⌊ a b ⌋ )
那么在递归的过程中使用 exgcd(b,a%b,y,x)
就可以让 x
直接获得解,然后只需要计算 y
的值就好了
在 C++
中,整数除法默认向下取整,故可以写成 y=y-a/b*x
的形式
根据递归求解的正确性,可以确定递归结果是正确的
注 意 , 这 里 的 x 与 y 的 正 负 是 未 知 的 注 意 , 这 里 的 x 与 y 的 正 负 是 未 知 的
两个定理
定理一:对于不定方程 a x + b y = c , c % gcd ( a , b ) = 0 a x + b y = c , c % gcd ( a , b ) = 0 ,一定存在整数解为 ( c gcd ( a , b ) x , c gcd ( a , b ) y ) ( c gcd ( a , b ) x , c gcd ( a , b ) y ) (这个应该没必要证明了吧)
定理二:若 ( x , y ) ( x , y ) 是不定方程 a x + b y = gcd ( a , b ) a x + b y = gcd ( a , b ) 的一组整数解,则 ( x + k b gcd ( a , b ) , y − k a gcd ( a , b ) ) ( x + k b gcd ( a , b ) , y − k a gcd ( a , b ) ) 也是方程的一组整数解
证 明 设 d = gcd ( a , b ) 设 ( x 1 , y 1 ) 和 ( x 2 , y 2 ) 均 为 方 程 a x + b y = d 的 整 数 解 , 则 a x 1 + b y 1 = d a x 2 + b y 2 = d ( 1 ) − ( 2 ) ⇒ a ( x 1 − x 2 ) + b ( y 1 − y 2 ) = 0 ⇒ a d ( x 1 , x 2 ) = − b d ( y 1 − y 2 ) ∵ d = gcd ( a , b ) ∴ gcd ( a d , b d ) = 1 ∴ b d | ( x 1 − x 2 ) ∴ x 1 − x 2 = k b d ⇒ x 1 = x 2 + k b d 联 立 ( 1 ) , ( 3 ) , 有 a ( x 2 − k b d ) + b y 1 = d ⇒ a x 2 + k a b d + b y 1 = d 联 立 ( 2 ) , ( 4 ) , 有 d − b y 2 + k a b d + b y 1 = d ∴ y 1 = y 2 − k a d 得 证 (1) (2) (3) (4) 证 明 设 d = gcd ( a , b ) 设 ( x 1 , y 1 ) 和 ( x 2 , y 2 ) 均 为 方 程 a x + b y = d 的 整 数 解 , 则 (1) a x 1 + b y 1 = d (2) a x 2 + b y 2 = d ( 1 ) − ( 2 ) ⇒ a ( x 1 − x 2 ) + b ( y 1 − y 2 ) = 0 ⇒ a d ( x 1 , x 2 ) = − b d ( y 1 − y 2 ) ∵ d = gcd ( a , b ) ∴ gcd ( a d , b d ) = 1 ∴ b d | ( x 1 − x 2 ) (3) ∴ x 1 − x 2 = k b d ⇒ x 1 = x 2 + k b d 联 立 ( 1 ) , ( 3 ) , 有 a ( x 2 − k b d ) + b y 1 = d (4) ⇒ a x 2 + k a b d + b y 1 = d 联 立 ( 2 ) , ( 4 ) , 有 d − b y 2 + k a b d + b y 1 = d ∴ y 1 = y 2 − k a d 得 证
应用扩展欧几里得求乘法逆元
定义
对于 a x ≡ 1 ( mod p ) a x ≡ 1 ( mod p ) ,x 为 a 在 模 p 意 义 下 的 逆 元 x 为 a 在 模 p 意 义 下 的 逆 元
换言之,对于方程 a x + b y = 1 , gcd ( a , b ) = 1 a x + b y = 1 , gcd ( a , b ) = 1 , x ∈ [ 1 , b ) x ∈ [ 1 , b ) 是 a a 在模 b b 意义下的逆元
用法
那么我们就可以用 exgcd
求解这个方程,这样就得到了逆元
template <class T >inline T gcd (T a,T b,T&x,T&y) {
if (b==0 ){
x=1 ,y=0 ;return a;
}
T g=gcd (b,a%b,y,x);
y=y-a/b*x;
return g;
}
inline int sol (int a,int p) {
int x,y;
int g=gcd (a,p,x,y);
int ans=x,t=0 ;
while ((ans=x+b/g*t)<1 )t++;
while ((ans=x+b/g*t)>=p)t--;
return ans;
}
这里用到了一个定理:
定理二:若 ( x , y ) ( x , y ) 是不定方程 a x + b y = gcd ( a , b ) a x + b y = gcd ( a , b ) 的一组整数解,则 ( x + k b gcd ( a , b ) , y − k a gcd ( a , b ) ) ( x + k b gcd ( a , b ) , y − k a gcd ( a , b ) ) 也是方程的一组整数解
作用是确保 x ∈ [ 1 , p ) x ∈ [ 1 , p )
e.g.
给定 n n 个正整数 a i a i , p = 10 9 + 7 p = 10 9 + 7 ,求
n ∑ i = 1 ( a − 1 i × 998244353 n − i ) ( mod p ) ∑ i = 1 n ( a i − 1 × 998244353 n − i ) ( mod p )
解 : 由 a x ≡ 1 ( mod p ) 知 : x = 1 a ( mod p ) 设 { a n } 是 题 目 所 给 出 的 数 组 则 其 逆 元 可 表 示 为 : { 1 a n } 设 { s i } 中 s i = a 1 × a 2 × ⋯ × a i 则 s i = s i − 1 × a i ∴ 1 s i = 1 s i − 1 × a i ∴ 1 s i − 1 = 1 s i × a i ∴ 1 a i = s i − 1 s i ∵ a i 已 知 , s i 可 以 线 性 推 导 ∴ 可 以 线 性 推 导 出 1 s n ∴ 可 以 再 次 线 性 推 导 出 1 s i , 进 而 求 出 1 a i (1) (2) (3) 解 : 由 a x ≡ 1 ( mod p ) 知 : x = 1 a ( mod p ) 设 { a n } 是 题 目 所 给 出 的 数 组 则 其 逆 元 可 表 示 为 : { 1 a n } 设 { s i } 中 s i = a 1 × a 2 × ⋯ × a i (1) 则 s i = s i − 1 × a i ∴ 1 s i = 1 s i − 1 × a i (2) ∴ 1 s i − 1 = 1 s i × a i (3) ∴ 1 a i = s i − 1 s i ∵ a i 已 知 , s i 可 以 线 性 推 导 ∴ 可 以 线 性 推 导 出 1 s n ∴ 可 以 再 次 线 性 推 导 出 1 s i , 进 而 求 出 1 a i
#include <bits/stdc++.h>
using namespace std;
#define GO(u,v,i) for(int i=u;i<=v;i++)
template <class t >inline t fr () {
register t num=0 ,dis=1 ;
register char ch=getchar ();
while (ch<'0' ||ch>'9' ){if (ch=='-' )dis=-1 ;ch=getchar ();}
while (ch>='0' &&ch<='9' ){num=(num<<1 )+(num<<3 )+(ch^48 );ch=getchar ();}
return num*dis;
}
template <class t >inline void fw (t num) {
if (num>9 )fw (num/10 );
putchar (num%10 +'0' );
}
template <class t >inline void fw (t num,char ch) {
if (num<0 )num=-num,putchar ('-' );
fw (num);putchar (ch);
}
const int maxn=5e6 +12 ;
typedef long long lld;
const lld p=1e9 +7 ,k=998244353 ;
int n;
lld a[maxn],s[maxn],sns[maxn],an[maxn];
lld anss;
template <class t >inline t gcd (t a,t b,t&x,t&y) {
if (b==0 ){
x=1 ,y=0 ;
return a;
}
t g=gcd (b,a%b,y,x);
y=y-a/b*x;
return g;
}
template <class t >inline t power (t num,t tim) {
t ans=1 ;
GO (1 ,tim,i)ans*=num;
return ans;
}
inline void sol () {
n=fr <int >();
s[0 ]=1 ;
GO (1 ,n,i){
a[i]=fr <lld>();
s[i]=(s[i-1 ]*a[i])%p;
}
lld x,y;
lld g=gcd (s[n],p,x,y);
lld ans=x,t=0 ;
while ((ans=x+p/g*t)<1 )t++;
while ((ans=x+p/g*t)>=p)t--;
sns[n]=ans;
lld tmp=1 ;
for (int i=n;i>0 ;i--){
sns[i-1 ]=(sns[i]*a[i])%p;
an[i]=(sns[i]*s[i-1 ])%p;
anss+=(an[i]*tmp)%p;
tmp*=k;tmp%=p;
}
fw (anss%p,'\n' );
}
signed main () {
sol ();
return 0 ;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律