一个整数除以3余2、除以5余3、除以7余2,求这个整数?答案:23
分解为子问题,得同余方程 (这个是中国剩余定理的内容,下面是拓展欧几里得)
转化为(p2 * p3) * x + p1 * y = 1形式
求 x
求 (p2 * p3) * x 和
最小正数处理
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL ex_gcd(LL a, LL b, LL &x, LL &y)
{
if (b == 0)
{
x = 1;
y = 0;
return a;
}
LL gcd = ex_gcd(b, a % b, x, y);
LL tmp = x;
x = y;
y = tmp - a / b * y;
return gcd;
}
int main() // ax + np = 1
{
LL mod3, mod5, mod7;
cin >> mod3 >> mod5 >> mod7;
LL yy1, yy2, yy3; // a[] = 35, 21, 15 p[] = 3, 5, 7
LL x[4], n[4];
LL gcd1 = ex_gcd(35, 3, x[1], n[1]);
LL gcd2 = ex_gcd(21, 5, x[2], n[2]);
LL gcd3 = ex_gcd(15, 7, x[3], n[3]);
if (gcd1 != 1 || gcd2 != 1 || gcd3 != 1)
{
cout << "No solution" << endl;
return 0;
}
yy1 = 35 * x[1];
yy2 = 21 * x[2];
yy3 = 15 * x[3];
LL ans = mod3 * yy1 + mod5 * yy2 + mod7 * yy3;
LL mod = 3 * 5 * 7;
cout << (ans % mod + mod) % mod;
return 0;
}
思考
退回同余方程,用把未知数看成逆元,用小费马定理求解
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
LL qmi(LL base, LL expo, LL mod)
{
LL retv = 1;
while (expo)
{
if (expo & 1)
retv = (retv * base) % mod;
base = (base * base) % mod;
expo >>= 1;
}
return retv;
}
int main()
{
LL mod3, mod5, mod7;
cin >> mod3 >> mod5 >> mod7;
LL yy1, yy2, yy3;
LL x[4];
x[1] = qmi(35, 3 - 2, 3);
x[2] = qmi(21, 5 - 2, 5);
x[3] = qmi(15, 7 - 2, 7);
yy1 = 35 * x[1];
yy2 = 21 * x[2];
yy3 = 15 * x[3];
LL ans = mod3 * yy1 + mod5 * yy2 + mod7 * yy3;
LL mod = 3 * 5 * 7;
cout << (ans % mod + mod) % mod;
return 0;
}