题解:P2485 [SDOI2011] 计算器

### 思路

本题是一个比较模板化的题目。

#### 一操作

考虑使用快速幂。

快速幂,只需要把 $k$ 变成二进制即可实现 $\Theta(\log k)$ 的时间复杂度。

实现方法:

```cpp
long long qmi(long long a,long long k,long long p){
    long long res = 1;
    while (k){
        if (k & 1){
            res = (res * a) % p;
        }
        a = (a * a) %p;
        k >>= 1;
    }
    return res;
}
```

### 二操作

考虑使用乘法逆元,除一个数等于乘上那个数的逆元,当 $p$ 为质数时,$x$ 的逆元为 $x^{p-2}$。

计算 $x^{p-2}$ 也可以使用快速幂。

### 三操作

考虑使用 BSGS 算法来进行计算,具体实现代码如下:

```cpp
long long bsgs(long long a,long long b,long long p){
    unordered_map<long long,long long>mp;
    if (1 % p == b % p){
        return 0;
    }
    long long k = sqrt(p) + 1;
    for (long long i = 0,j = b % p; i < k; i ++ ){
        mp[j] = i;
        j = (long long)j * a % p;
    }
    long long t = 1 % p;
    for (long long i = 0; i < k; i ++ ){
        t = (long long)t * a % p;
    }
    for (long long i = 1,j = t; i <= k; i ++ ){
        if (mp.count(j)){
            return (long long)i * k - mp[j];
        }
        j = (long long)j * t % p;
    }
    return -1;
}
```

### 最终代码

只需要把给出的那些东西合并起来即可。

```cpp
#include <bits/stdc++.h>
using namespace std;
long long qmi(long long a,long long k,long long p){
    long long res = 1;
    while (k){
        if (k & 1){
            res = (res * a) % p;
        }
        a = (a * a) %p;
        k >>= 1;
    }
    return res;
}
long long bsgs(long long a,long long b,long long p){
    unordered_map<long long,long long>mp;
    if (1 % p == b % p){
        return 0;
    }
    long long k = sqrt(p) + 1;
    for (long long i = 0,j = b % p; i < k; i ++ ){
        mp[j] = i;
        j = (long long)j * a % p;
    }
    long long t = 1 % p;
    for (long long i = 0; i < k; i ++ ){
        t = (long long)t * a % p;
    }
    for (long long i = 1,j = t; i <= k; i ++ ){
        if (mp.count(j)){
            return (long long)i * k - mp[j];
        }
        j = (long long)j * t % p;
    }
    return -1;
}
int main(){
    long long n,T;
    cin >> n >> T;
    if (T == 1){
        for (long long i = 1; i <= n; i ++ ){
            long long a,b,p;
            cin >> a >> b >> p;
            cout << qmi(a,b,p) << endl;
        }
    } 
    else if (T == 2){
        for (int i = 1;  i<= n; i ++ ){
            int a,b,p;
            cin >> a >> b >> p;
            a %= p,b %= p;
            if (a == 0 && b != 0){
                cout << "Orz, I cannot find x!" << endl;
            }
            else{
                cout << qmi(a,p - 2,p) * b % p << endl;
            }
        }
    }
    else{
        for (long long i = 1; i <= n; i ++ ){
            long long a,b,p;
            cin >> a >> b >> p;
            if (a % p == b % p){
                cout << 1 << endl;
                continue;
            }
            a %= p;
            long long t = bsgs(a,b,p);
            if (a == 0 && b == 0){
                cout << 1 << endl;
            }
            else if (a == 0 && b != 0){
                cout << "Orz, I cannot find x!" << endl;
            }
            else{
                if (t == -1){
                    cout << "Orz, I cannot find x!" << endl;
                }
                else{
                    cout << t << endl;
                }
            }
        }
    }
    return 0;
}
```

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值