Aug 5, 2019 由 小羊
题目链接:HDU 6632
已知数字 ,并且 。想求解离散对数 。
需要一个东西叫做 Pohlig-Hellman 算法。以下是来自维基百科内容的翻译,将使用群论语言。
这个算法用于计算 阶循环群 的离散对数 。
初始化
计算 ,由拉格朗日配集分解计数定理知,。
对于 ,分别做
计算 。由此构造可知,此元素的阶一定整除 ,即阶为 或 ,因此 。
使用 BSGS 算法,计算 ,其中 。这个操作的复杂度为
令
返回
当 时,这个算法优于 BSGS,复杂度为 。
首先我们将 的阶数刻画为 。现在我们解方程 。
对循环群阶数做因数分解
对于 ,分别做
计算 ,由拉格朗日定理知此元素的阶为 。
计算 ,由此构造知
利用上面算法计算 使得
利用中国剩余定理解方程组
返回
因此总的时间复杂度为
显然因为 ,我们不用 BSGS……好的。
#include <bits/stdc++.h>
using namespace std;
typedef long long lld;
lld fpow(lld _a, lld k, lld MOD) {
__int128 b = 1, a = _a % MOD;
while (k) {
if (k & 1) b = b * a % MOD;
a = a * a % MOD;
k >>= 1;
}
return b;
}
__int128 extgcd(__int128 a, __int128 b, __int128 &x, __int128 &y) {
if (!b) return x = 1, y = 0, a;
__int128 d = extgcd(b, a % b, y, x);
return y -= (a / b) * x, d;
}
int T, e2, e3, G;
lld MOD, n, p2, p3;
lld solvePE(lld g, lld h, lld p, lld pe, int e)
{
lld x = 0, pp = 1;
lld y = fpow(g, pe/p, MOD);
for (int k = 0; k < e; k++)
{
__int128 hk = fpow(g, pe-x, MOD);
hk = hk * h % MOD;
hk = fpow(hk, pe/p/pp, MOD);
__int128 d, yy;
for (d = 0, yy = 1; d < p; d++, yy = yy * y % MOD)
if (yy == hk) break;
x = (x + pp * d) % MOD, pp *= p;
}
return x;
}
__int128 solveN(lld h)
{
if (e3 == 0) return solvePE(G, h, 2, p2, e2);
else if (e2 == 0) return solvePE(G, h, 3, p3, e3);
__int128 x2 = solvePE(fpow(G, p3, MOD), fpow(h, p3, MOD), 2, p2, e2);
__int128 x3 = solvePE(fpow(G, p2, MOD), fpow(h, p2, MOD), 3, p3, e3);
__int128 invp2, invp3; assert(extgcd(p2, p3, invp2, invp3) == 1);
return (x2 * p3 * invp3 + x3 * p2 * invp2) % (MOD-1);
}
int main()
{
cin >> T;
while (T--)
{
long long a, b;
cin >> MOD >> a >> b;
n = MOD-1, e2 = e3 = 0, p2 = p3 = 1;
while (n % 2 == 0) n /= 2, p2 *= 2, e2++;
while (n % 3 == 0) n /= 3, p3 *= 3, e3++;
for (G = 2; (e2 > 0 && fpow(G, (MOD-1)/2, MOD) == 1)
|| (e3 > 0 && fpow(G, (MOD-1)/3, MOD) == 1); G++);
__int128 inda = solveN(a), indb = solveN(b), x, y;
__int128 d = extgcd(inda, MOD-1, x, y);
lld ans = indb % d ? -1
: lld((indb / d * x % (MOD-1) + (MOD-1)) % ((MOD-1)/d));
cout << ans << endl;
}
return 0;
}
我竟然都忘了 extgcd 是怎么求多解的,我好菜啊QAQ