【模板】exBSGS/Spoj3105 Mod

【模板】exBSGS/Spoj3105 Mod

题目描述

已知数(a,p,b),求满足(a^xequiv b pmod p)的最小自然数(x)

输入输出格式

输入格式:

每个测试文件中最多包含(100)组测试数据。

每组数据中,每行包含(3)个正整数(a,p,b)

(a=p=b=0)时,表示测试数据读入完全。

输出格式:

对于每组数据,输出一行。

如果无解,输出No Solution(不含引号),否则输出最小自然数解。


BSGS

(A perp p),那么({A^x,xle varphi(p)})遍历的剩余系({A^{kx},xle varphi(p)})一定也遍历,于是考虑枚举答案

[A^xequiv B pmod p ]

采用分块的思想,设(t=sqrt p,x=kt-b),式子就变成了

[A^{kt-b}equiv B pmod p ]

[A^{kt}equiv A^bBpmod p ]

我们枚举(x=0 sim t),然后把得到的(A^xB)插到( t{Hash})表中去。

然后枚举((A^t)^k)(k),查询( t{Hash})表中有没有(A^{kt})

exBSGS

如果(p)不是质数,存在无解的判定((gcd(A,p) mid B))(B ot=1)((B=1)特判(x=0))

然后考虑操作一波式子

[A^xequiv 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})

原方程变为

[CAequiv B' pmod {p'} ]

然后重复是否无解的判断并向下递归,直到(Aperp 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
",ans);
        else puts("No Solution");
        scanf("%d%d%d",&a,&p,&b);
    }
    return 0;
}

2018.12.19

原文地址:https://www.cnblogs.com/butterflydew/p/10143327.html