BZOJ3122 随机数生成器——BSGS

题意

链接

给定 $p,\ a,\ b, \ x_1$,现有一数列

$$x_{i+1} \equiv (ax_i + b) \ mod \ p$$

求最小的 $i$ 满足 $x_i = t$

分析

代码

#include<bits/stdc++.h>
using namespace std;

typedef long long ll;

//ax + by = d,且|x|+|y|最小,其中d=gcd(a,b)
//即使a, b在int范围内,x和y也有可能超过int范围
void exgcd(ll a, ll b, ll &d, ll &x, ll &y)
{
    if (!b){ d = a; x = 1; y = 0;}
    else{ exgcd(b, a % b, d, y, x); y -= x * (a / b);}
}

//计算模n下a的逆。如果不存在逆,返回-1
//ax=1(mod n)
ll inv(ll a, ll n)
{
    ll d, x, y;
    exgcd(a, n, d, x, y);
    return d == 1 ? (x + n) % n : -1;
}

inline ll bsgs(ll a, ll b, ll p) {
    a %= p;
    b %= p;
    std::map<ll, ll> map;
    ll m = ceil(sqrt(p)), t = 1;
    for (int i = 0; i < m; i++) {
        if (!map.count(t)) map[t] = i;
        t = t * a % p;
    }

    ll k = inv(t, p), w = b;
    for (int i = 0; i < m; i++) {
        if (map.count(w)) return i * m + map[w];
        w = w * k % p;
    }

    return -1;
}

inline ll solve(ll p, ll a, ll b, ll x1, ll t) {
    if (t == x1) return 1;
    else if (a == 0) return b == t ? 2 : -1;
    else if (a == 1) {
        if (!b) return -1;
        return ((((t - x1) % p + p) % p) * inv(b, p) % p) + 1;
    } else {
        ll q = inv(1 - a + p, p);
        ll d = (((t - b * q) % p + p) % p) * inv(((x1 - b * q) % p + p) % p, p);
        ll ans = bsgs(a, d, p);
        if (ans == -1) return -1;
        else return ans + 1;
    }
}


int main() {
    int T;
    scanf("%d", &T);
    while (T--) {
        int p, a, b, x1, t;
        scanf("%d %d %d %d %d", &p, &a, &b, &x1, &t);
        printf("%lld\n", solve(p, a, b, x1, t));
    }
}

发现BZOJ还能下测试数据:https://darkbzoj.tk/data/

 

参考链接:https://oi.men.ci/sdoi2013-random/

个性签名:时间会解决一切
posted @ 2019-07-30 13:25  Rogn  阅读(205)  评论(0编辑  收藏  举报