luogu P3306 [SDOI2013] 随机数生成器

https://www.luogu.com.cn/problem/P3306
首先根据小学知识可以把原式子写成等比数列的形式
X i + 1 + b a − 1 = a ( x i + b a − 1 ) m o d    p X_{i+1}+\frac{b}{a-1}=a(x_i+\frac{b}{a-1}) \mod p Xi+1+a1b=a(xi+a1b)modp
所以
X n + b a − 1 = a n − 1 ( x 1 + b a − 1 ) m o d    p X_{n}+\frac{b}{a-1}=a^{n-1}(x_1+\frac{b}{a-1}) \mod p Xn+a1b=an1(x1+a1b)modp
a n − 1 = . . . . m o d    p a^{n-1}=....\mod p an1=....modp
这坨东西就可以大力BSGS了
注意一下边界就好了
code:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll mod;
ll qpow(ll x, ll y) {
    ll ret = 1;
    for(; y; y >>= 1, x = x * x % mod) if(y & 1) ret = ret * x % mod;
    return ret;
}
map<ll, ll> mp;
ll BSGS(ll a, ll b) {
    int m = sqrt(mod + 1);
    ll t = b % mod;
    mp.clear();
    for(int i = 0; i <= m; i ++, t = t * a % mod) mp[t] = i;
    a = qpow(a, m); t = a;
    if(!t) return b? -1 : 1;
    for(int i = 1; i <= m + 1; i ++, t = t * a % mod) {
        int j = mp.find(t) == mp.end()? -1 : mp[t];
        if(j != -1) return 1ll * i * m - j;
    }
    return - 2;
}
int T;
ll s, t, a, b;
int main() {
    scanf("%d", &T);
    while(T --) {
        scanf("%lld%lld%lld%lld%lld", &mod, &a, &b, &s, &t);
        if(s == t) {puts("1"); continue;}
        if(a == 0) {printf("%d\n", t == b? 2 : -1); continue;}
        if(a == 1) {
            if(! b) puts("-1");
            else {
                printf("%lld\n", (t - s + mod) % mod * qpow(b, mod - 2) % mod + 1);
            }
            continue;
        }
        ll y = b * qpow(a - 1, mod - 2) % mod;
        t = (t + y) % mod, s = qpow(s + y, mod - 2);
        printf("%lld\n", BSGS(a, t * s % mod) + 1);
    }
    return 0;
}
posted @ 2021-07-16 19:54  lahlah  阅读(24)  评论(0编辑  收藏  举报