2019牛客暑期多校训练营(第五场)C generator 2 (BSGS)

2019牛客暑期多校训练营(第五场)C generator 2

思路

x 0 = x 0 x_0 = x_0

x 1 = a x 0 b x_1 = a * x_0 * b

x 2 = a x 1 + b = a 2 x 0 + a b + b x_2 = a * x_1 + b = a ^{2} * x_0 + a * b + b

容易发现后项是一个等比数列求和

x n = a n x 0 + b ( 1 a n ) 1 a x_n = a ^ {n} x_0 + \frac {b (1 - a ^ n)} {1 - a}

我们要求 x n = v x_n = v ,化简

a n x 0 + b ( 1 a n ) 1 a = v a ^ {n} x_0 + \frac {b (1 - a ^ n)} {1 - a} = v

a n x 0 ( 1 a ) + b ( 1 a n ) = v ( 1 a ) a ^{n} x_0(1 - a) + b (1 - a ^ n) = v(1 - a)

a n ( x 0 a x 0 b ) = v ( 1 a ) b a ^ n (x_0 - ax_0 - b) = v(1 - a) - b

a n = v ( 1 a ) b x 0 a x 0 b a^n =\frac {v (1 - a) - b} {x_0 - a x_0 - b}

上面式子都是 m o d    p \mod p 下的同余等式,为了方便写了 = =

看到这里就简单了,我们要求解的是 n n ,显然右边这一坨都是已知的,我们假定为 B B ,求解 a n = B a ^ n = B ,这不就是个裸题了吗。

这道题目还要稍加分类讨论一下:

  • a == 0

x 0 = x 0 , x i = b ( i > = 1 ) x_0 = x_0, x_i = b(i >= 1)

  • a = = 1 a == 1

因为这种情况上面不能直接相除,所以我们需要特殊考虑 a i = b + i a a_i = b + i * a

也就是求解 i a = v b i * a = v - b ,这个时候只要左右两边同时乘以 a a 的逆元即可得到我们要的 i i

代码

/*
  Author : lifehappy
*/
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#include <bits/stdc++.h>
#define mp make_pair
#define pb push_back
#define endl '\n'

using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;

const double pi = acos(-1.0);
const double eps = 1e-7;
const int inf = 0x3f3f3f3f;

inline ll read() {
    ll f = 1, x = 0;
    char c = getchar();
    while(c < '0' || c > '9') {
        if(c == '-') f = -1;
        c = getchar();
    }
    while(c >= '0' && c <= '9') {
        x = (x << 1) + (x << 3) + (c ^ 48);
        c = getchar();
    }
    return f * x;
}

void print(ll x) {
    if(x < 10) {
        putchar(x + 48);
        return ;
    }
    print(x / 10);
    putchar(x % 10 + 48);
}

ll quick_pow(ll a, ll n, ll mod) {
    ll ans = 1;
    while(n) {
        if(n & 1) ans = (ans * a) % mod;
        a = (a * a) % mod;
        n >>= 1;
    }
    return ans;
}

int main() {
    // freopen("in.txt", "r", stdin);
    // freopen("out.txt", "w", stdout);
    // ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);
    int T = read();
    while(T--) {
        ll n = read(), x0 = read(), a = read(), b = read(), p = read();
        ll x = 1, Unit = quick_pow(a, 1000, p);
        unordered_map<ll, int> MP;
        for(int i = 1; i <= 1000000; i++) {
            x = (x * Unit) % p;
            if(!MP.count(x)) {
                MP[x] = i * 1000;
            }
        }
        ll inv = quick_pow(((x0 - a * x0 - b) % p + p) % p, p - 2, p);
        int t = read();
        while(t--) {
            ll v = read();
            if(a == 0) {
                if(v % p == x0 % p) {
                    puts("0");
                }
                else if(v % p == b % p) {
                    puts("1");
                }
                else {
                    puts("-1");
                }
                continue;
            }
            if(a == 1) {
                ll ans = (((((v - x0) % p + p) % p) * quick_pow(b, p - 2, p))) % p;
                if(ans < n) {
                    printf("%lld\n", ans);
                }
                else {
                    puts("-1");
                }
                continue;
            }
            v = (((v * (1 - a) - b) % p + p) % p * inv) % p;
            if(Unit == 0) {
                if(v == 0) {
                    puts("0");
                }
                else {
                    puts("-1");
                }
                continue;
            }
            x = v;
            int ans = p + 1;
            for(int i = 0; i <= 1000; i++) {
                if(MP.count(x)) {
                    ans = min(ans, MP[x] - i);
                }
                x = (x * a) % p;
            }
            if(ans != p + 1 && ans < n) {
                printf("%d\n", ans);
            }
            else {
                puts("-1");
            }
        }
    }
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_45483201/article/details/107631906