BSGS (大步小步算法)
已知\(a、b、 c\),求\(x\)。令\(a^x \equiv b \pmod c\)。
步骤
\[m = \lceil \sqrtc\ \rceil \]\[x = i*m-j\ \ (i\in[1, m], j\in[0, m])\]\[a^{i*m-j} \equiv b \pmod c\]\[a^{i*m}\equiv b*a^j \pmod c\]
枚举\(a^j(j\in[0, m])\)放入\(hash\)表里面,再枚举\(a^{i*m}\),在\(hash\)表里面找有没有相同,如若有相同的那么就存在。
如果在询问较多的情况下,可以把\(bm = \lceil c^{\frac{2}{3}}\rceil\)、\(gm = \lceil c^{\frac{1}{3}}\rceil\)\((i\in[1,gm],j\in[0, bm])\)
实现代码
struct Hash{
int head[maxm], cnt, mod;
struct Node{
int v, id, next;
}node[maxn];
void init(){
mes(head, -1);
cnt = 0;
mod = 1333331;
}
void insert(int x, int id){
int u = x%mod;
node[++cnt].v = x;
node[cnt].id = id;
node[cnt].next = head[u];
head[u] = cnt;
}
int find(int x){
int u = x%mod;
for(int i = head[u]; ~i; i = node[i].next){
if(node[i].v == x)
return node[i].id;
}
return -1;
}
}hs;
ll qpow(ll a, ll b, int mod){
ll ans = 1;
while(b){
if(b&1)
ans = ans*a%mod;
a = a*a%mod;
b /= 2;
}
return ans;
}
struct BSGS{
int bm, gm, a, b, x0, p;
void init(){
bm = (int)ceil(pow(p, 2.0/3));
gm = (int)ceil(pow(p, 1.0/3));
ll ans = 1;
hs.init();
for(int i = 0; i <= bm; i++){ //a^(i*bm - j)%p = b;
hs.insert(ans, i);
ans = ans*a%p;
}
}
ll get(ll v){
v = qpow(v, p-2, p);
ll num = qpow(a, bm, p);
for(int i = 1; i <= gm; i++){
v = v*num%p;
int ans = hs.find(v);
if(ans != -1)
return 1ll*i*bm - ans;
}
return -1;
}
}bsgs;
例题
牛客多校训练营第五场 - generator 2
\(x_n = (a*x_{n-1} + b)\%p\),给你\(n、x_0、a、b、p\),\(Q\)个询问在\(x_0,x_1,x_2...,x_{n-1}\)找到最小符合\(x_i = v\)的\(i\),不存在输出\(-1\)。
思路
\[x_n = a*x_{n-1} + b\]\[x_n = a^n *x_0+b*\frac{1-a^n}{1-a}\]\[a^n = \frac{(a-1)_*x_n+b}{(a-1)*x_0+b}\]\[x_n = v, 令B = \frac{(a-1)_*v+b}{(a-1)*x_0+b}\]所以就是求\[a^n \equiv B\pmod p\]
\(a = 0、a = 1\)的情况要特殊考虑一下
AC代码
#include