1. 程式人生 > 實用技巧 >[SDOI2011]計算器

[SDOI2011]計算器

題目描述

你被要求設計一個計算器完成以下三項任務: 1、給定y,z,p,計算Y^Z Mod P 的值; 2、給定y,z,p,計算滿足xy≡ Z ( mod P )的最小非負整數; 3、給定y,z,p,計算滿足Y^x ≡ Z ( mod P)的最小非負整數。

輸入描述:

輸入包含多組資料。
第一行包含兩個正整數T,K分別表示資料組數和詢問型別(對於一個測試點內的所有資料,詢問型別相同)。
以下行每行包含三個正整數y,z,p,描述一個詢問。

輸出描述:

對於每個詢問,輸出一行答案。對於詢問型別2和3,如果不存在滿足條件的,則輸出“Orz, I cannot find x!”,注意逗號與“I”之間有一個空格。

輸入

3 1
2 1 3
2 2 3
2 3 3

輸出

2
1
2

輸入

3 2
2 1 3
2 2 3
2 3 3

輸出

2
1
0

備註:

【資料規模和約定】
對於100%的資料,1<=y,z,p<=10^9,為質數,1<=T<=10。
// 數論常見三種操作
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
LL ksm(LL a, LL b, LL p) {
    LL ans = 1 % p;
    while (b) {
        
if (b & 1) ans = ans * a % p; a = a * a % p; b >>= 1; } return ans; } LL exgcd(LL a, LL b, LL& x, LL& y) { if (b == 0) { x = 1; y = 0; return a; } LL d = exgcd(b, a % b, x, y); LL z = x; x = y; y = z - y * (a / b); return d; } LL baby_step_giant_step(LL a, LL b, LL p) { map
<LL, LL> hash; hash.clear(); b %= p; LL t = sqrt(p) + 1; for (LL j = 0; j < t; j++) { LL val = b * ksm(a, j, p) % p; hash[val] = j; } a = ksm(a, t, p); if (a == 0) return b == 0 ? 1 : -1; for (LL i = 0; i <= t; i++) { LL val = ksm(a, i, p); LL j = hash.find(val) == hash.end() ? -1 : hash[val]; if (j >= 0 && i * t - j >= 0) return i * t - j; } return -1; } void solve(int tp) { LL y, z, p, x, t; cin >> y >> z >> p; if (tp == 1) { cout << ksm(y, z, p) << endl; } else if (tp == 2) { // y * x - z = p * t y * x + p * t = z LL g = exgcd(y, p, x, t); if (z % g) cout << "Orz, I cannot find x!" << endl; else { x *= z / g; p /= g; cout << (x % p + p) % p << endl; } } else { LL ans = baby_step_giant_step(y, z, p); if (ans == -1) cout << "Orz, I cannot find x!" << endl; else cout << ans << endl; } } int main() { int T, K; while (cin >> T >> K) { while (T--) { solve(K); } } return 0; }