gcd and exgcd

数论入门基础

最大公约数

问题1

给定平面上的两个格点

P1=(x1,y1)
P2=(x2,y2)
求线段P1P2上有几个格点
109<=x1,x2,y1,y2<=109

解法1

枚举所有的合法的

min(x1,x2)<=x<=max(x1,x2)

min(y1,y2)<=y<=max(y1,y2)

判断 (x,y) 是否在线段上

数据范围大,我们需要更快的算法

解法2

假设我们从(x1,y1)出发已经找到了离它最近的一个格点P0,那么从P0出发走相同长度肯定也是一个整数格点,就这样一路找下去,最终恰好能找到(x2, y2),中间的每一段都是等长的,你可以假设最终到的点不是(x2,y2),而是延伸出去的某个点,那么显然P0就不是离(x1, y1)最近的一个格点了。
所以我们证明了一个性质

线段上的所有的整数格点恰好都在这条线段的K等分点上

要满足等分点都是整数,所以K必须为X距离和Y距离的公约数,我们需要求最大的K,所以就是两个距离的最大公约数了

求最大公约数的欧几里德算法

  • 更相减损术
  • 辗转相除法

这两种方法是一样的,下面是上面的优化

int gcd(int a, int b) {
    while(a != b) {
        if (a > b) {
            a -= b;
        } else {
            b -= a;
        }
    }
    return a;
}
int gcd(int a, int b) {
    if(b == 0) return a;
    return gcd(b, a % b);
}

为什么这样子做是对的呢?
假设 g 为a b的某个公约数,那么对于任意一个g都有如下两个式子

a=k1g

b=k2g

a b更相减损,变的只是前面的k,无论怎么减g还是他们的约数,一直到最后两个数变成相同的,g还是他们的约数 这个时候他们相视一笑,发现原来你也在这里 也就是说

在更相减损的过程当中,所有的公约数信息都没有丢,也不会增加,跟原来一样,但是数据变小了哦,那么一直变小会发生什么呢?

对于任意一个公约数g都满足最后变成的两个相等的数为g的倍数。所以辗转相减之后的数也是最大公约数 gmx 的倍数,假设最后得到的两个数是

k1g
k2g

既然所有的公约数信息都没丢,这两个数的公约数也是原来a b的公约数,那么 k1k2 的值必定为1,不然就存在某个比g大的公约数了,与g是最大公约数矛盾。

其实上面的辗转相减法,每次就是最大公约数的两个系数k1, k2在辗转相减,最终变成1(他们的最大公约数是1),这个辗转相减的过程可以描述为

k1x+k2y=1

所以这个方程其实一定有解,因为刚才已经证明k1 k2辗转相减一定能得到他们的最大公约数1。

扩展欧几里得

问题

一个游戏
有向前向后无线延续的格子, 每个格子都写有整数。其中0号格子是起点, 1号格子是终点。 而骰子上只有a,b,-a,-b四个整数,所以根据a和b的值得不同,有可能无法到达终点。掷出四个整数各多少次可以到达终点?

解法

上述问题归结起来就是

ax+by=1;

如果
gcd(a,b)!=1
,无解。
实际上一定存在整数对(x, y)使得
ax+by=gcd(a,b)

假设已经求得了

1: bx+(a%b)y=gcd(a,b)

的整数解 (x,y)

a%b=a(a/b)b;

代入可得
bx+(a(a/b)b)y=gcd(a,b)

化简一下

2: ay+b(x(a/b)y)=gcd(a,b)

所以,解出了1式,就可以由2式得到原方程的解
特殊的,当b = 0时,

a1+b0=gcd(a,b)=a;

下面的代码解决 ax+by=gcd(a,b)

int extgcd(int a, int b, int &x, int &y) {
    int d = a;
    if(b != 0) {
        d = extgcd(b,  a % b,  x,  y);
        x -= (a / b) * y;
        std::swap(x,  y);
    } else {
        x = 1; y = 0; // g x+ 0 * y = g, y can be any number
    }
    return d;
}

递归算到最后y其实可以取任意整数。但是取的太大容易导致使得最后算出来的解爆int之类的事情
下面我们来看一下最终算出来的解 x0 y0 的绝对值大小情况
由x y的计算方法x -= (a / b) * y可以知道,x y始终是在max(|a|, |b|)的绝对值范围内的,因此a*x + b*y = gcd(a, b)最后算出的x y的绝对值大小跟a b是同一个级别的。
扩展欧几里德其实就是欧几里德,欧几里德其实就是辗转相减,全是一样的!

通解:

  • 4
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,我可以为您完成这个需求。 首先,根据RSA算法的原理,我们可以得到私钥d的计算公式为: d ≡ e^-1 (mod φ(n)) 其中,n = p * q,φ(n) = (p-1) * (q-1)。 根据给定的p和q,我们可以先求出n和φ(n): n = p * q = 11 * 13 = 143 φ(n) = (p-1) * (q-1) = 10 * 12 = 120 然后,我们需要计算e的逆元e^-1。为了求出e^-1,我们可以使用扩展欧几里得算法。具体地,我们可以定义一个函数exgcd(a, b, x, y),用来求ax + by = gcd(a, b)的一组整数(x, y)。然后,我们可以使用exgcd函数求出e和φ(n)的最大公约数gcd(e, φ(n)),以及对应的一组整数(x, y)。由于e和φ(n)互质,因此gcd(e, φ(n))应该等于1。此时,x就是e的逆元e^-1。如果x为负数,则我们需要将其加上φ(n),使其变为正数。 下面是exgcd函数的代码实现: ```cpp int exgcd(int a, int b, int& x, int& y) { if (b == 0) { x = 1; y = 0; return a; } int d = exgcd(b, a % b, y, x); y -= a / b * x; return d; } ``` 接下来,我们可以使用exgcd函数计算出e^-1的值: ```cpp int e = 17; int phi = 120; int d, x, y; int gcd = exgcd(e, phi, x, y); if (gcd != 1) { // e和phi(n)不互质,无法计算私钥 } else { d = x < 0 ? x + phi : x; } ``` 最后,我们可以根据RSA算法的公式实现加密和密过程。具体地,加密过程如下: 1. 将明文转换为对应的整数m。 2. 计算密文c = m^e (mod n)。 密过程如下: 1. 将密文转换为对应的整数c。 2. 计算明文m = c^d (mod n)。 下面是完整的代码实现: ```cpp #include <iostream> using namespace std; int exgcd(int a, int b, int& x, int& y) { if (b == 0) { x = 1; y = 0; return a; } int d = exgcd(b, a % b, y, x); y -= a / b * x; return d; } int pow_mod(int a, int b, int n) { int res = 1; while (b > 0) { if (b & 1) { res = (res * a) % n; } a = (a * a) % n; b >>= 1; } return res; } int encrypt(int m, int e, int n) { return pow_mod(m, e, n); } int decrypt(int c, int d, int n) { return pow_mod(c, d, n); } int main() { int p = 11, q = 13, e = 17; int n = p * q; int phi = (p - 1) * (q - 1); int d, x, y; int gcd = exgcd(e, phi, x, y); if (gcd != 1) { cout << "Error: e and phi(n) are not coprime." << endl; return 0; } else { d = x < 0 ? x + phi : x; } int m = 123; int c = encrypt(m, e, n); int m2 = decrypt(c, d, n); cout << "Original message: " << m << endl; cout << "Encrypted message: " << c << endl; cout << "Decrypted message: " << m2 << endl; return 0; } ``` 运行结果如下: ``` Original message: 123 Encrypted message: 76 Decrypted message: 123 ``` 因此,加密后的密文为76。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值