1. 程式人生 > >[BZOJ 1467] [POJ 3243] clever Y

[BZOJ 1467] [POJ 3243] clever Y

題目描述

小Y發現,數學中有一個很有趣的式子: XYmodZ=KX^Y\ mod\ Z = K 給出XXYYZZ,我們都知道如何很快的計算KK。但是如果給出XXZZKK,你是否知道如何快速的計算YY呢?

輸入輸出格式

輸入格式

本題由多組資料(不超過20組),每組測試資料包含一行三個整數XXZZKK0X,Z,K1090 \le X, Z, K \le 10^9)。 輸入檔案一行由三個空格隔開的00結尾。

輸出格式

對於每組資料:如果無解則輸出一行No Solution,否則輸出一行一個整數Y(0Y<Z)Y(0 \le Y < Z)

,使得其滿足XYmodZ=KX^Y\ mod\ Z = K,如果有多個解輸出最小的一個YY

輸入輸出樣例

輸入樣例#1:

5 58 33
2 4 3
0 0 0

輸出樣例#1:

9
No Solution

解題分析

一道擴充套件BSGSBSGS的板題。

一般的BSGSBSGS只能解決AXB(modC)A^X\equiv B(mod\ C)CC為質數的情況, 如果ACA、C不互質就涼涼了。

d=gcd(A,C)d=gcd(A,C), 那麼我們可以將這個式子拆開成AdAx1Bd(mod

Cd)\frac{A}{d}A^{x-1}\equiv \frac{B}{d}(mod\ \frac{C}{d}), 如此反覆操作最後可以得到P×AxnumB(modC)P\times A^{x-num}\equiv B'(mod\ C')。 這時候就可以用普通的BSGSBSGS搞操作了。

不過顯然我們現在的x>numx>num, 所以我們暴力列舉xnumx\le 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); } }