1. 计算pow(a, b)
2. 线性同余方程
3. 高次同余方程

分析

pow(a, b)

qword qpow(qword a, qword b, qword p) {
a %= p; qword res = 1 % p; for (; b; b >>= 1, a = a * a % p) if (b & 1) res = res * a % p; return res;
}


线性同余方程

Bezout(贝祖)定理：对于任意整数 $a, b$，存在一对整数 $x, y$，满足 $ax + by = gcd(a, b)$

$b = 0$时， 显然有一对整数 $x = 1, y = 0$ 使得 $a * 1 + 0 * 0 = gcd(a, 0)$
$b > 0$，则 $gcd(a, b) = gcd(b, a \bmod b)$。假设存在一对整数 $x, y$ 满足 $b * x + (a \bmod b) * y = gcd(b, a \bmod b)$.

Bezout定理是按照欧几里得算法的流程进行证明的，所以这种能同时计算 $x, y$ 的算法叫做扩展欧几里得算法

qword exgcd(qword a, qword b, qword &x, qword &y) {
if (b == 0) { x = 1, y = 0; return a; }
qword d = exgcd(b, a % b, x, y);
qword z = x; x = y; y = z - y * (a / b);
return d;
}


高次同余方程

$x = i * t - j$ 其中 $t = [\sqrt{p}], 0 \le j \le t - 1$，则方程变为 $a ^{i * t - j} = b \pmod p$,即 $(a^t)^i = b * a ^ j \pmod p$

qword baby_step_gaint_step(qword a, qword b, qword p) {
mp.clear();
b %= p;
qword t = (qword)sqrt(p) + 1;
for (int j = 0; j < t; ++ j) {
qword val = (qword)b * qpow(a, j, p) % p;
mp[val] = j;
}
a = qpow(a, t, p);
if (a == 0) return b == 0 ? 1 : -1;
for (int i = 0; i <= t; ++ i) {
qword val = qpow(a, i, p);
qword j = mp.find(val) == mp.end() ? -1 : mp[val];
if (j >= 0 && i * t - j >= 0) return i * t - j;
}
return -1;
}


完整代码

#include <bits/stdc++.h>
using namespace std;

typedef long long qword;

qword qpow(qword a, qword b, qword p) {
a %= p; qword res = 1 % p; for (; b; b >>= 1, a = a * a % p) if (b & 1) res = res * a % p; return res;
}

qword exgcd(qword a, qword b, qword &x, qword &y) {
if (b == 0) { x = 1, y = 0; return a; }
qword d = exgcd(b, a % b, x, y);
qword z = x; x = y; y = z - y * (a / b);
return d;
}

map<qword, qword> mp;

qword baby_step_gaint_step(qword a, qword b, qword p) {
mp.clear();
b %= p;
qword t = (qword)sqrt(p) + 1;
for (int j = 0; j < t; ++ j) {
qword val = (qword)b * qpow(a, j, p) % p;
mp[val] = j;
}
a = qpow(a, t, p);
if (a == 0) return b == 0 ? 1 : -1;
for (int i = 0; i <= t; ++ i) {
qword val = qpow(a, i, p);
qword j = mp.find(val) == mp.end() ? -1 : mp[val];
if (j >= 0 && i * t - j >= 0) return i * t - j;
}
return -1;
}

qword t, op, x, y;

int main() {
cin >> t >> op;
for (int i = 1, a, b, p; i <= t; ++ i) {
cin >> a >> b >> p;
if (op == 1) cout << qpow(a, b, p) << endl;
else if (op == 2) {
qword d = exgcd(a, p, x, y);
if (b % d) cout << "Orz, I cannot find x!" << endl;
else {
x *= b / d;
cout << (x % p + p) % p << endl;
}
} else if (op == 3){
x = baby_step_gaint_step(a, b, p);
if (x == -1) cout << "Orz, I cannot find x!" << endl;
else cout << (x % p + p) % p << endl;
}
}
return 0;
}

posted @ 2018-10-05 11:35  AlessandroChen  阅读(284)  评论(0编辑  收藏  举报