BZOJ传送门
POJ传送门
题目描述
小Y发现,数学中有一个很有趣的式子: X Y m o d Z = K X^Y\ mod\ Z = K XY mod Z=K 给出 X X X、 Y Y Y、 Z Z Z,我们都知道如何很快的计算 K K K。但是如果给出 X X X、 Z Z Z、 K K K,你是否知道如何快速的计算 Y Y Y呢?
输入输出格式
输入格式
本题由多组数据(不超过20组),每组测试数据包含一行三个整数 X X X、 Z Z Z、 K K K( 0 ≤ X , Z , K ≤ 1 0 9 0 \le X, Z, K \le 10^9 0≤X,Z,K≤109)。 输入文件一行由三个空格隔开的 0 0 0结尾。
输出格式
对于每组数据:如果无解则输出一行No Solution
,否则输出一行一个整数
Y
(
0
≤
Y
<
Z
)
Y(0 \le Y < Z)
Y(0≤Y<Z),使得其满足
X
Y
m
o
d
Z
=
K
X^Y\ mod\ Z = K
XY mod Z=K,如果有多个解输出最小的一个
Y
Y
Y。
输入输出样例
输入样例#1:
5 58 33
2 4 3
0 0 0
输出样例#1:
9
No Solution
解题分析
一道扩展 B S G S BSGS BSGS的板题。
一般的 B S G S BSGS BSGS只能解决 A X ≡ B ( m o d C ) A^X\equiv B(mod\ C) AX≡B(mod C)且 C C C为质数的情况, 如果 A 、 C A、C A、C不互质就凉凉了。
设 d = g c d ( A , C ) d=gcd(A,C) d=gcd(A,C), 那么我们可以将这个式子拆开成 A d A x − 1 ≡ B d ( m o d C d ) \frac{A}{d}A^{x-1}\equiv \frac{B}{d}(mod\ \frac{C}{d}) dAAx−1≡dB(mod dC), 如此反复操作最后可以得到 P × A x − n u m ≡ B ′ ( m o d C ′ ) P\times A^{x-num}\equiv B'(mod\ C') P×Ax−num≡B′(mod C′)。 这时候就可以用普通的 B S G S BSGS BSGS搞操作了。
不过显然我们现在的 x > n u m x>num x>num, 所以我们暴力枚举 x ≤ n u m x\le num x≤num的情况就好。
代码如下:
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
#include <cmath>
#include <cctype>
#include <map>
#define W while
#define IN inline
#define gc getchar()
#define R register
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc);
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
}
std::map <int, int> mp;
int exgcd(R int a, R int b, int &x, int &y)
{
if(!b) return x = 1, y = 0, a;
int ret = exgcd(b, a % b, x, y);
int buf = x; x = y, y = buf - a / b * y;
return ret;
}
IN int EXBSGS(R int A, R int B, R int MOD)
{
if(MOD == 1) if(!B) return 0; else return -1;
if(B == 1) if(A) return 0; else return -1;
if(!(A % MOD)) if(!B) return 1; else return -1;
int num = 0, now = 1, seg = 1, gcd, x, y, bd = std::ceil(std::sqrt(MOD));
mp.clear();
W ((gcd = exgcd(A, MOD, x, y)) > 1)
{
if(B % gcd) return -1;
B /= gcd, MOD /= gcd; ++num;
now = 1ll * now * A / gcd % MOD;
}
for (R int i = 0, val = 1; i <= num; ++i, val = 1ll * val * A % MOD)
if(val == B) return i;
for (R int i = 0; i < bd; ++i, seg = 1ll * seg * A % MOD) if(!mp.count(seg)) mp[seg] = i;
for (R int i = 0; i < bd; ++i, now = 1ll * now * seg % MOD)
{
gcd = exgcd(now, MOD, x, y);
x = (1ll * x * B % MOD + MOD) % MOD;
if(mp.count(x)) return i * bd + mp[x] + num;
}
return -1;
}
int main(void)
{
R int A, B, MOD, ans;
W (~scanf("%d%d%d", &A, &MOD, &B))
{
if(!(A | B | MOD)) break;
ans = EXBSGS(A, B, MOD);
if(ans < 0) puts("No Solution");
else printf("%d\n", ans);
}
}