最大公约数:
定义:
若自然数d同时是自然数a和b的约数,则称d是a和b的公约数。a和b的公约数中最大的数g则称为a和b的最大公约数,即为gcd(a,b)。
欧几里得算法
描
述
:
∀
a
,
b
∈
N
,
b
≠
0
,
g
c
d
(
a
,
b
)
=
g
c
d
(
b
,
a
%
b
)
;
描述:\forall a,b \in N,b \ne 0,gcd(a,b) = gcd(b,a\%b);
描述:∀a,b∈N,b=0,gcd(a,b)=gcd(b,a%b);
证
明
:
若
a
<
b
,
则
g
c
d
(
b
,
a
%
b
)
=
g
c
d
(
b
,
a
)
=
g
c
d
(
a
,
b
)
;
若
a
>
=
b
,
设
a
=
q
∗
b
+
r
,
其
中
b
∈
[
0
,
b
)
,
显
然
r
=
a
%
b
,
设
g
=
g
c
d
(
a
,
b
)
,
则
有
g
∣
a
,
g
∣
q
∗
b
,
则
有
g
∣
(
a
−
q
∗
b
)
,
即
g
∣
r
,
因
此
g
也
为
r
和
b
的
最
大
公
约
数
,
即
g
c
d
(
a
,
b
)
=
g
c
d
(
b
,
a
%
b
)
,
证
毕
!
证明:若a < b,则gcd(b,a\%b) = gcd(b,a) = gcd(a,b);若a>=b,\\设a = q*b+r,其中b\in[0,b),显然r = a\%b,设g = gcd(a,b),则有\\g|a,g|q*b,则有g|(a-q*b),即g|r,因此g也为r和b的最大公约数,\\即gcd(a,b) = gcd(b,a\%b),证毕!
证明:若a<b,则gcd(b,a%b)=gcd(b,a)=gcd(a,b);若a>=b,设a=q∗b+r,其中b∈[0,b),显然r=a%b,设g=gcd(a,b),则有g∣a,g∣q∗b,则有g∣(a−q∗b),即g∣r,因此g也为r和b的最大公约数,即gcd(a,b)=gcd(b,a%b),证毕!
int gcd(int a,int b)
{
return b?gcd(b,a%b):a;
}
最小公倍数
定义:
若自然数m同时自然数a,b的倍数,则称m是a,b的公倍数。在a和b中所有的公倍数最小的一个则成为最小公倍数,记为lcm(a,b)。易证lcm(a,b) = a*b/gcd(a,b)。
例题讲解:
For a given positive integer n denote its k-rounding as the minimum positive integer x, such that x ends with k or more zeros in base 10 and is divisible by n.
For example, 4-rounding of 375 is 375·80 = 30000. 30000 is the minimum integer such that it ends with 4 or more zeros and is divisible by 375.
Write a program that will perform the k-rounding of n.
分析:题目等效于求出n和pow(10,k)的最小公约数。
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
using namespace std;
typedef long long ll;
int gcd(int a,int b)
{
if(!b) return a;
else return gcd(b,a%b);
}
ll lcm(int a,int b)
{
return (ll)a*b/gcd(a,b);
}
int main()
{
int n,k;cin >> n >> k;
cout << lcm(n,pow(10,k)) << endl;
return 0;
}
同余
定义
若 整 数 a , b 除 以 正 整 数 m 的 余 数 相 等 , 则 称 a , b 模 m 同 余 , 记 为 a ≡ b ( m o d m ) 若整数a,b除以正整数m的余数相等,则称a,b模m同余,记为a\equiv b(mod\ m) 若整数a,b除以正整数m的余数相等,则称a,b模m同余,记为a≡b(mod m)
欧拉定理
若 正 整 数 a , n 互 质 , 则 a φ ( n ) ≡ 1 ( m o d n ) , 其 中 φ ( n ) 为 欧 拉 函 数 . 证 明 : 设 n 的 简 化 剩 余 系 为 { b 1 ‾ , b 2 ‾ , . . . , b φ ( n ) ‾ } 。 对 ∀ b i , b j , 若 a ∗ b i ≡ a ∗ b j ( m o d n ) , 则 有 a ∗ ( b i − b j ) ≡ 0 ( m o d n ) . 因 为 a , n 互 质 , 所 以 ( b i − b j ) ≡ 0 ( m o d n ) , 即 b i ≡ b j ( m o d n ) . 故 当 b i ≠ b j 时 , a b i , a b j 也 代 表 不 同 的 同 余 类 。 天 堂 > > > 制 造 > > > 证 毕 ! 若正整数a,n互质,则a^{\varphi(n)} \equiv1(mod\ n),其中\varphi(n)为欧拉函数.\\证明:设n的简化剩余系为 \{\overline{b_{1} }, \overline{b_{2} },...,\overline{b_{\varphi(n)} }\}。对\forall b_i,b_j,若\\a*b_i \equiv a*b_j(mod\ n),则有a*(b_i-b_j)\equiv 0(mod\ n).\\因为a,n互质,所以(b_i-b_j)\equiv 0(mod\ n),即b_i\equiv b_j(mod\ n).故当\\b_i\ne b_j时,ab_i,ab_j也代表不同的同余类。天堂>>>制造>>>证毕! 若正整数a,n互质,则aφ(n)≡1(mod n),其中φ(n)为欧拉函数.证明:设n的简化剩余系为{b1,b2,...,bφ(n)}。对∀bi,bj,若a∗bi≡a∗bj(mod n),则有a∗(bi−bj)≡0(mod n).因为a,n互质,所以(bi−bj)≡0(mod n),即bi≡bj(mod n).故当bi=bj时,abi,abj也代表不同的同余类。天堂>>>制造>>>证毕!
费马小定理
若 p 是 质 数 , 则 对 于 任 意 整 数 a , 有 a p ≡ a ( m o d p ) 。 证 明 : 用 欧 拉 定 理 证 明 。 若p是质数,则对于任意整数a,有a^p\equiv a(mod\ p)。\\证明:用欧拉定理证明。 若p是质数,则对于任意整数a,有ap≡a(mod p)。证明:用欧拉定理证明。
例题讲解
要求(A/B)%9973,但由于A很大,我们只给出n(n=A%9973)(我们给定的A必能被B整除,且gcd(B,9973) = 1)。
分析:费马小定理运用快速幂求逆元即可.
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int mod = 9973;
ll qpow(ll n,ll m)
{
ll ans = 1;
while(m)
{
if(m&1)
{
--m;
ans *= n;
ans %= mod;
}
else
{
m >>= 1;
n *= n;
n %= mod;
}
}
return ans;
}
int main()
{
int T;cin >> T;
while(T--)
{
ll a,b;cin >> a >> b;
a %= mod;
ll ans = a*qpow(b,mod-2);
ans %= mod;
cout << ans << endl;
}
return 0;
}
拓展欧几里得算法
对 于 任 意 正 整 数 a , b , 存 在 一 对 整 数 x , y , 满 足 a x + b y = g c d ( a , b ) . 对于任意正整数a,b,存在一对整数x,y,满足ax+by = gcd(a,b). 对于任意正整数a,b,存在一对整数x,y,满足ax+by=gcd(a,b).
int x,y;
int exgcd(int a,int b)
{
if(!b){ x = 1,y = 0;return a;}
int d = exgcd(b,a%b);
int z = x,x = y,y = z-y*(a/b);
return d;
}
例题讲解:
两只青蛙在网上相识了,它们聊得很开心,于是觉得很有必要见一面。它们很高兴地发现它们住在同一条纬度线上,于是它们约定各自朝西跳,直到碰面为止。可是它们出发之前忘记了一件很重要的事情,既没有问清楚对方的特征,也没有约定见面的具体位置。不过青蛙们都是很乐观的,它们觉得只要一直朝着某个方向跳下去,总能碰到对方的。但是除非这两只青蛙在同一时间跳到同一点上,不然是永远都不可能碰面的。为了帮助这两只乐观的青蛙,你被要求写一个程序来判断这两只青蛙是否能够碰面,会在什么时候碰面。
我们把这两只青蛙分别叫做青蛙A和青蛙B,并且规定纬度线上东经0度处为原点,由东往西为正方向,单位长度1米,这样我们就得到了一条首尾相接的数轴。设青蛙A的出发点坐标是x,青蛙B的出发点坐标是y。青蛙A一次能跳m米,青蛙B一次能跳n米,两只青蛙跳一次所花费的时间相同。纬度线总长L米。现在要你求出它们跳了几次以后才会碰面。
分析:列出方程组后通过转化即可利用拓展欧几里得算法即可算出答案;
#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cmath>
using namespace std;
typedef long long ll;
const ll INF = -1;
ll x,y;
ll gcd(ll a,ll b)
{
if(!b) return a;
else return gcd(b,a%b);
}
void ex_gcd(ll a,ll b)
{
if(!b)
{
x = 1;
y = 0;
return;
}
ex_gcd(b,a%b);
ll t = x;
x = y;
y = t-a/b*y;
return ;
}
int main()
{
ll d1,d2,m,n,b;cin >> d1 >> d2 >> m >> n >> b;
ll a,c;
if(n > m){a = n-m;c = d1-d2;}
else {a = m-n;c = d2-d1;}
ll g = gcd(a,b);
ex_gcd(a,b);
ll ans;
if(c%g) ans = INF;
else
ans = (c/g*x%(b/g)+b/g)%(b/g);
if(ans == INF)
cout << "Impossible" << endl;
else
cout << ans << endl;
return 0;
}