题意:
传送门
已知递推公式(x_i = a*x_{i - 1} + bmod p),(p)是素数,已知(x_0,a,b,p),给出一个(n)和(v),问你满足(x_i = v)且(i < n)的最小的(i)是多少。
思路:
经过一些举例我们可以发现(x_i = a^ix_0 + bfrac{a^i-1}{a-1}mod p),当(a
eq 1)可得(a^i = frac{(a-1)v+b}{(a-1)x_0+b}mod p)。再当(a geq 1)时可用(BSGS)求解,其他直接特判。
但是因为(q)的存在,如果直接套模板复杂度(O(sqrt p + qsqrt 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
");
else if(v == b && n - 1 >= 1) printf("1
");
else printf("-1
");
}
else if(a == 1){
v = ((v - x0) % p + p) % p;
if(b == 0){
printf("%d
", v == 0? 0 : -1);
continue;
}
ll ans = 1LL * v * ppow(b, p - 2, p) % p;
printf("%lld
", 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
", ans >= n? -1 : ans);
}
}
}
return 0;
}