【模板】exBSGS/Spoj3105 Mod
【模板】exBSGS/Spoj3105 Mod
题目描述
已知数\(a,p,b\),求满足\(a^x\equiv b \pmod p\)的最小自然数\(x\)。
输入输出格式
输入格式:
每个测试文件中最多包含\(100\)组测试数据。
每组数据中,每行包含\(3\)个正整数\(a,p,b\)。
当\(a=p=b=0\)时,表示测试数据读入完全。
输出格式:
对于每组数据,输出一行。
如果无解,输出No Solution
(不含引号),否则输出最小自然数解。
BSGS
若\(A \perp p\),那么\(\{A^x,x\le \varphi(p)\}\)遍历的剩余系\(\{A^{kx},x\le \varphi(p)\}\)一定也遍历,于是考虑枚举答案
\[A^x\equiv B \pmod p
\]
采用分块的思想,设\(t=\sqrt p,x=kt-b\),式子就变成了
\[A^{kt-b}\equiv B \pmod p
\]
\[A^{kt}\equiv A^bB\pmod p
\]
我们枚举\(x=0 \sim t\),然后把得到的\(A^xB\)插到\(\tt{Hash}\)表中去。
然后枚举\((A^t)^k\)的\(k\),查询\(\tt{Hash}\)表中有没有\(A^{kt}\)
exBSGS
如果\(p\)不是质数,存在无解的判定\((\gcd(A,p)\nmid B)\)且\(B\not=1\)(\(B=1\)特判\(x=0\))
然后考虑操作一波式子
\[A^x\equiv B \pmod p,d=\gcd(A,p)
\]
把\(d\)除掉
\[A^{x-1}\frac{A}{d}\equiv \frac{B}{d}\pmod {\frac{p}{d}}
\]
设\(C=\frac{A}{d},B'=\frac{B}{d},p'=\frac{p}{d}\)
原方程变为
\[CA\equiv B' \pmod {p'}
\]
然后重复是否无解的判断并向下递归,直到\(A\perp p\)或者无解
然后\(BSGS\)即可,而常数\(C\)并不影响我们进行\(BSGS\)
复杂度?显然递归的深度是\(\log\)的,带上BSGS的就可以了。
Code:
#include <cstdio>
#include <cmath>
#include <unordered_map>
std::unordered_map <int,int> Hash;
int gcd(int a,int b){return b?gcd(b,a%b):a;}
#define mul(a,b,p) (1ll*(a)*(b)%p)
int exbsgs(int A,int B,int p)
{
if(B==1) return 0;
int ct=0,d,k=1;
while((d=gcd(A,p))^1)
{
if(B%d) return -1;
B/=d,p/=d,++ct;
k=mul(k,A/d,p);
if(k==B) return ct;
}
int t=sqrt(p)+1,kt=1;
Hash.clear();
for(int i=0;i<t;i++)
{
Hash[mul(kt,B,p)]=i;
kt=mul(kt,A,p);
}
k=mul(k,kt,p);
for(int i=1;i<=t;i++)
{
if(Hash.find(k)!=Hash.end()) return i*t-Hash[k]+ct;
k=mul(k,kt,p);
}
return -1;
}
int main()
{
int a,p,b;
scanf("%d%d%d",&a,&p,&b);
while(a&&p&&b)
{
int ans=exbsgs(a,b,p);
if(~ans) printf("%d\n",ans);
else puts("No Solution");
scanf("%d%d%d",&a,&p,&b);
}
return 0;
}
2018.12.19