1. 程式人生 > >【模板】exBSGS/Spoj3105 Mod

【模板】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