2019牛客多校第五场C generator 2(BSGS)题解
阅读原文时间:2023年07月09日阅读:2

题意:

传送门

已知递推公式\(x_i = a*x_{i - 1} + b\mod p\),\(p\)是素数,已知\(x_0,a,b,p\),给出一个\(n\)和\(v\),问你满足\(x_i = v\)且\(i < n\)的最小的\(i\)是多少。

思路:

经过一些举例我们可以发现\(x_i = a^ix_0 + b\frac{a^i-1}{a-1}\mod p\),当\(a \neq 1\)可得\(a^i = \frac{(a-1)v+b}{(a-1)x_0+b}\mod p\)。再当\(a \geq 1\)时可用\(BSGS\)求解,其他直接特判。

但是因为\(q\)的存在,如果直接套模板复杂度\(O(\sqrt p + q\sqrt p)\),\(3e7*T\)必\(TLE\)。因为每组询问的预处理都相同,那么我们不妨把预处理扩大,这样每次查询所要暴力的次数就变小了。预处理大小设为\(1e6\),手写\(Hash\)更快。

代码:

#include<map>
#include<set>
#include<queue>
#include<stack>
#include<ctime>
#include<cmath>
#include<cstdio>
#include<string>
#include<vector>
#include<cstring>
#include<sstream>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 300 + 5;
const int INF = 0x3f3f3f3f;
const ull seed = 131;
const ll MOD = 1e9;
using namespace std;

//BSGS
const int M = 5e6;
int hs[M], head[M], nex[M], id[M], top;
void _insert(ll x, int y){
    int k = x % M;
    hs[top] = x, id[top] = y, nex[top] = head[k], head[k] = top++;
}
int _find(ll x){
    int k = x % M;
    for(int i = head[k]; i != -1; i = nex[i]){
        if(hs[i] == x) return id[i];
    }
    return -1;
}
ll ppow(ll a, ll b, ll mod){
    ll ret = 1;
    while(b){
        if(b & 1) ret = ret * a % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return ret;
}
ll loop, up;
void preBSGS(ll p, ll a){   // a^x = b mod p
    memset(head, -1, sizeof(head));
    top = 1;
    up = ceil(1e6);
    ll t = 1;
    for(int i = 0; i <= up; i++){
        if(i == up) loop = t;
        _insert(t, i);
        t = 1LL * t * a % p;
    }
}
ll BSGS(ll A, ll B, ll P){  // a^x = b mod p
    ll m = ceil(P * 1.0 / 1e6);
    ll obj = ppow(B, P - 2, P), x;
    for(int i = 1; i <= m; i++){
        obj = 1LL * obj * loop % P;
        if((x = _find(obj)) != -1){
            return 1LL * i * up - x;
        }
    }
    return -1;
}
ll n, x0, a, b, p, Q;
int main(){
    int T;
    scanf("%d", &T);
    while(T--){
        scanf("%lld%lld%lld%lld%lld", &n, &x0, &a, &b, &p);
        scanf("%lld", &Q);
        preBSGS(p, a);
        while(Q--){
            ll v;
            scanf("%lld", &v);
            if(a == 0){
                if(v == x0) printf("0\n");
                else if(v == b && n - 1 >= 1) printf("1\n");
                else printf("-1\n");
            }
            else if(a == 1){
                v = ((v - x0) % p + p) % p;
                if(b == 0){
                    printf("%d\n", v == 0? 0 : -1);
                    continue;
                }
                ll ans = 1LL * v * ppow(b, p - 2, p) % p;
                printf("%lld\n", ans >= n? -1 : ans);

            }
            else{
                ll ret = (a * v % p - v + b) % p;
                ret = ret * ppow((a * x0 - x0 + b) % p, p - 2, p) % p;
                ret = (ret + p) % p;
                ll ans = BSGS(a, ret, p);
                printf("%lld\n", ans >= n? -1 : ans);
            }
        }
    }
    return 0;
}