同余问题共7part,我的博客链接:
高次同余方程
只考虑: a x ≡ b ( m o d m ) a^x\equiv b(\mod m) ax≡b(modm)
为保持统一,放一下手写的哈希(来自kuangbin的模板)
// (x,y)的HASH
#define MOD 76543
int hs[MOD], head[MOD], nxt[MOD], id[MOD], top;
void insert(int x, int y)
{
int k = x % MOD;
hs[top] = x, id[top] = y, nxt[top] = head[k], head[k] = top++;
}
int find(int x)
{
int k = x % MOD;
for (int i = head[k]; i != -1; i = nxt[i])
if (hs[i] == x)
return id[i];
return -1;
}
BSGS算法
gcd ( a , m ) = 1 \gcd(a,m)=1 gcd(a,m)=1 ,令 x = k s − t , s = ⌈ m ⌉ , 0 ≤ t < s , 0 < k ≤ s + 1 x=ks-t,s=\lceil \sqrt m\rceil,0\leq t<s,0<k\leq s+1 x=ks−t,s=⌈m⌉,0≤t<s,0<k≤s+1 ( s s s 的取值有严格证明这样复杂度最低),则原式变为 a k s ≡ b a t ( m o d m ) a^{ks}\equiv ba^{t}(\mod m) aks≡bat(modm) ,枚举可能的 t t t ,存下 b a t ba^t bat 的哈希值,再枚举左边的 k k k 算 a k s a^{ks} aks 查表。
// 普通BSGS: a^x==b mod m, gcd(a,m)=1
int BSGS(int a, int b, int m)
{
if(b == 1 || m == 1) // 注意这里的特判
return 0;
int s = sqrt(m) + 1;
memset(head,-1,sizeof(head));
top=0;
for (int i = 0, tmp = b; i < s; i++, tmp = tmp * a % m)
insert(tmp, i);
int as = qpow(a, s, m); // 快速幂算a^s
for (int i = 1, tmp = as; i <= s + 1; i++, tmp = tmp * as % m)
{
int qry = find(tmp);
if (qry == -1)
continue;
return i * s - qry;
}
return -1;
}
扩展BSGS算法
gcd
(
a
,
m
)
=
d
≠
1
\gcd(a,m)=d\neq 1
gcd(a,m)=d=1 ,等价变换为
a
x
+
m
y
=
b
a^x+my=b
ax+my=b 有解的条件是
d
∣
b
d\mid b
d∣b 。两边同除
d
d
d ,则变为
a
d
a
x
−
1
+
y
m
d
=
b
d
\frac{a}{d}a^{x-1}+y\frac{m}{d}=\frac{b}{d}
daax−1+ydm=db 不断检查
gcd
(
b
d
,
a
)
\gcd(\frac{b}{d},a)
gcd(db,a) 并除掉,直到为
1
1
1 。
记每次除的数乘积为
D
D
D ,则原式变为
a
k
D
a
x
−
k
+
y
m
D
=
b
D
\frac{a^k}{D}a^{x-k}+y\frac{m}{D}=\frac{b}{D}
Dakax−k+yDm=Db 即
a
x
−
k
≡
b
D
D
a
k
(
m
o
d
m
D
)
a^{x-k}\equiv \frac{b}{D}\frac{D}{a^k}(\mod \frac{m}{D})
ax−k≡DbakD(modDm) 用BSGS求解即可。
int exBSGS(int a, int b, int m)
{
if (b == 1 || m == 1)
return 0;
int k = 0, atmp = 1;
while (1)
{
int tmp = __gcd(m, a);
if (tmp == 1)
break;
if(b % tmp)
return -1;
b /= tmp, m /= tmp, k++;
atmp = atmp * (a / tmp) % m;
if (b == atmp)
return k;
}
return BSGS(a, b * inv(atmp, m) % m, m) + k;
}