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

可以得出通项公式:

Xn=an1×X1+b×i=0n2ai X n = a n − 1 × X 1 + b × ∑ i = 0 n − 2 a i

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

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

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

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

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

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

这样就是BSGS的模板了。
不过要特判三个情况:
(1) t=X1 t = X 1 :答案为 1 1
(2)A=0 t=X1 t = X 1 时答案为 1 1 t=B时答案为 2 2 ,否则为1
(3) A=1 A = 1 t=X1 t = X 1 时答案为 1 1 B=0时答案为 1 − 1 ,否则 X X <script type="math/tex" id="MathJax-Element-2181">X</script>是一个等差数列,直接利用逆元计算即可。
代码:

#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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值