UVA10225题解
题意简述
给定三个正整数 $A$、$B$、$M$,其中 $A$、$M$ 互质,求最小的正整数 $L$ 满足:$A^L \equiv B \pmod M$。
题目分析
这个题是高次同余方程的模板题。对于高次同余方程问题,一个经典的算法就是 Baby Step,Giant Step 算法,简称 BSGS 算法。以下为其具体过程:
首先设 $L=x \times \lceil \sqrt{M} \rceil-y$ ,其中 $0 \leq y \leq \lceil \sqrt{M} \rceil$,那么就有 $A^{x \times \lceil \sqrt{M} \rceil-y}\equiv B \pmod M$,又可以转化为 $(A^{\lceil \sqrt{M} \rceil})^x \equiv B \times A^y \pmod M$。接下来,对所有 $y \in [0,\lceil \sqrt{M} \rceil]$,将其对应的 $B \times A^y$ 插入到一个哈希表中,然后枚举 $x \in [0,\lceil \sqrt{M} \rceil ]$ 的取值,计算出 $(A^{\lceil \sqrt{M} \rceil})^x $ 并查找在哈希表中有无与其对应的 $y$ 即可,最终答案就是 $L=x \times \lceil \sqrt{M} \rceil-y$,若在哈希表中没有对应的 $y$ 的值,那么无解。
至于该算法的时间复杂度,别的题解中没有进行详细解释,此处解释一下。由于 $A$、$M$ 互质,所以对于任意的正整数 $i$,有$A^i\equiv A^{i \mod M}\pmod M$。因此,若原方程有解,就有 $0 \leq L \leq M$,即$0 \leq x \times \lceil \sqrt{M} \rceil-y \leq M$。而$0 \leq y \leq \lceil \sqrt{M} \rceil$,从而有 $0 \leq x \leq \lceil \sqrt{M} \rceil$。因此我们枚举 $x$ 取值的时间复杂度为 $O(\sqrt{M})$,同样地,建立 $B \times A^y$ 的哈希表的时间复杂度也为 $O(\sqrt{M})$。而其中计算 $(A^{\lceil \sqrt{M} \rceil})^x $、$A^y$ 使得最终的时间复杂度需要乘上一个 $\log\sqrt{M}$,因此总时间复杂度为 $O(\sqrt{M}\log\sqrt{M})$。另外,在代码中,我使用了 STL 的 unordered_map 代替了手写的哈希表,因为这样非常方便
(其实是我懒得自己写了),不过常数较大,在数据较大时不建议使用,并且还容易 MLE。
最后附上代码:
#include<bits/stdc++.h>
using namespace std;
int a,b,m;
int pw(int a,int b,int m)//快速幂。
{
int res=1;
for(;b;b>>=1)
{
if(b&1)
res=(long long)res*a%m;
a=(long long)a*a%m;
}
return res;
}
int BSGS(int a,int b,int m)
{
unordered_map<int,int>hash;//哈希表。
hash.clear();
a%=m;
b%=m;
int t=(int)sqrt(m)+1;
for(int i=0;i<t;i++)//枚举B乘A的y次方,建立哈希表。
{
int val=(long long)b*pw(a,i,m)%m;
hash[val]=i;
}
a=pw(a,t,m);//计算A的根号M次方,不需要每次计算一遍。
for(int i=0;i<=t;i++)//枚举A的根号M次方的x次方,并在哈希表中查找对应的y。
{
int val=pw(a,i,m);
int j=hash.find(val)==hash.end()?-1:hash[val];
if(j>=0&&i*t-j>=0)
return i*t-j;
}
return -1;//无解
}
int main()
{
while(scanf("%d%d%d",&m,&a,&b)==3)
{
if(b==1)
{
printf("0\n");
continue;
}
int ans=BSGS(a,b,m);
if(ans>=0)
printf("%d\n",ans);
else
printf("no solution\n");
}
return 0;
}
本篇是本人的第二篇题解,希望审核大大可以给过