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;
}

本篇是本人的第二篇题解,希望审核大大可以给过

posted @ 2021-08-24 15:46  Hadtsti  阅读(0)  评论(0编辑  收藏  举报  来源