[BZOJ3122][Sdoi2013]随机数生成器(BSGS算法)

本文详细介绍了BSGS算法的推导过程及其在解决特定模意义下指数方程的应用。通过数学变换,将问题转化成易于求解的形式,并给出了具体的实现代码。此外,还特别讨论了三种特殊情况下的解法。

可以得出通项公式:

Xn=an1×X1+b×i=0n2aiXn=an−1×X1+b×∑i=0n−2ai

n2i=0ai∑i=0n−2ai是一个等比数列和的形式,所以转化为:
Xn=an1×X1+b×an11a1Xn=an−1×X1+b×an−1−1a−1

所以就是要求最小的nn使得:
an1×X1+b×an11a1t(modp)

两边同时乘以a(a1)a(a−1)
(a1)×an×X1+a×b×(an11)t×a×(a1)(modp)(a−1)×an×X1+a×b×(an−1−1)≡t×a×(a−1)(modp)

展开并移项:
an+1×X1an×X1+an×bt×a×(a1)+a×b(modp)an+1×X1−an×X1+an×b≡t×a×(a−1)+a×b(modp)

等号左边合并:
an×[(a1)×X1+b]t×a×(a1)+a×b(modp)an×[(a−1)×X1+b]≡t×a×(a−1)+a×b(modp)

再移项(1−1为乘法逆元):
an[t×a×(a1)+a×b]×[(a1)×X1+b]1(modp)an≡[t×a×(a−1)+a×b]×[(a−1)×X1+b]−1(modp)

这样就是BSGS的模板了。
不过要特判三个情况:
(1)t=X1t=X1:答案为11
(2)A=0t=X1t=X1时答案为11t=B时答案为22,否则为1
(3)A=1A=1t=X1t=X1时答案为11B=0时答案为1−1,否则XX是一个等差数列,直接利用逆元计算即可。
代码:
#include <map>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
inline int read() {
    int res = 0; bool bo = 0; char c;
    while (((c = getchar()) < '0' || c > '9') && c != '-');
    if (c == '-') bo = 1; else res = c - 48;
    while ((c = getchar()) >= '0' && c <= '9')
        res = (res << 3) + (res << 1) + (c - 48);
    return bo ? ~res + 1 : res;
}
int MX, A, B, X1, t, S, C;
map<int, int> ha;
inline int qpow(int a, int b, const int &MX) {
    int res = 1; while (b) b & 1 ? res = 1ll * res * a % MX : 0,
        a = 1ll * a * a % MX, b >>= 1; return res;
}
inline int BSGS() {
    int i, x = 1; for (i = 1; i <= S; ++i) {
        x = 1ll * x * A % MX; if (!ha[x]) ha[x] = i;
    }
    int dalao = qpow(x, MX - 2, MX), tmp = C;
    for (i = 0; i < S; ++i) {
        if (ha[tmp]) {
            int res = i * S + ha[tmp]; ha.clear(); return res;
        } 
        tmp = 1ll * tmp * dalao % MX;
    }
    ha.clear(); return -1;
}
inline void work() {
    MX = read(); A = read(); B = read(); X1 = read(); t = read();
    if (t == X1) return (void) puts("1");
    if (A == 0) {
        if (t == X1) puts("1"); else if (t == B) puts("2");
        else puts("-1"); return;
    }
    if (A == 1) {
        if (B == 0) return (void) puts("-1");
        int res = (t - X1 + MX) % MX;
        res = 1ll * res * qpow(B, MX - 2, MX) % MX;
        return (void) printf("%d\n", res + 1);
    }
    S = ceil(sqrt(MX)); int tmp = (A - 1 + MX) % MX;
    C = (1ll * t * A % MX * tmp % MX + 1ll * A * B % MX) % MX;
    C = 1ll * C * qpow((1ll * X1 * tmp % MX + B) % MX, MX - 2, MX) % MX;
    printf("%d\n", BSGS());
}
int main() {
    int T = read(); while (T--) work();
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值