1. 程式人生 > >高次同餘方程,二次同餘方程學習筆記

高次同餘方程,二次同餘方程學習筆記

寫在前面

文章作者實力有限,本文可能有個別錯誤,如有錯誤請友好指出。
高次同餘方程就是\(x^a\equiv b(mod\ p)\)
二次同餘方程就是\(x^2 \equiv b(mod \ p)\)
我們接下來討論解這兩種方程的方法。
那麼有一個問題。既然知道了高次同餘方程的解法,就可以直接用解高次同餘的方法解二次剩餘方程。為什麼要單獨學二次同餘方程呢。
因為我區間加區間修改用的是線段樹不是樹套樹。即問題特殊化之後可以使用一些特殊的方法,這種方法可能會比一般方法高效,簡便。

正文

高次同餘方程

首先需要知道原根

定義

滿足\(a^x\equiv 1(mod \ p)\)

的最小的正整數x是a關於模p的,接下來\(a\)的階表示為\(<a>\)

條件

\(gcd(a,p)=1\),這是顯然的。

性質

1\(<a>\mid \varphi(p)\)
證明:
因為\(a^{\varphi(p)}\equiv 1(mod\ p)\)\(a^{<a>}\equiv 1(mod\ p)\)
所以\(a^{\varphi(p)-<a>}\equiv 1(mod\ p)\)
進而得出\(a^{\varphi(p)\ mod \ <a>}\equiv 1(mod\ p)\)
假設\(<a>\)

不是\(\varphi(p)\)的約數。
\(\varphi(p)\ mod<a>\neq 0\)
\((\varphi(p)\ mod<a>)\ < \ (<a>)\)\(<a>\)的最小性矛盾,與假設矛盾原命題成立。
證畢。
推論:如果

2:設a關於模p的階為\(<a>\)\(a^0\)\(a^1\)\(a^2\),...,\(a^{<a>-1}\)兩兩不同
證明:
假設\(a^x\equiv1(mod\ p)\)\(a^y\equiv 1(mod \ p)\),且\(a^x\equiv a^y(mod\ p)\)

\(x<y\)
\(a^{y-x}\equiv 1(mod \ p)\)\(y-x<<a>\)與階的最小性矛盾,假設不成立,原命題成立。
證畢。

3:設a關於模p的階為\(<a>\)\(a^x\equiv a^y(mod\ p)\),的充要條件是\(x\equiv y(mod\ <a>)\)。兩邊一直除\(a^{<a>}\)因為\(a^{<a>}\equiv 1(mod\ p)\)所以結論顯然。

原根

(因為原根的定義涉及到階,所以預設互質,又因為原根的性質3,p為質數)

定義

滿足g關於模p的階等於\(\varphi(p)\)的g是p的一個原根。

性質

1:設g是模p的一個原根,那麼對於任意一個小於p的正整數x,都存在唯一一個值r使得r是以g為底的x對模p的指數。
其實就是說\(g^r\equiv x(mod\ p)\)的r是唯一的,反過來也一樣。其中g為p的一個原根,\(x<p\)\(r<\varphi (p)\)其實就是階的第二個性質。不再贅述。
2:對於一個質數,所擁有的原根個數是\(\varphi(\varphi(p))\)
3:一個模數存在原根的從要條件是,這個模數可以表示為\(1,2,4,p,2p,p^n\)其中\(p\)是奇質數,n是任意正整數
(這兩個性質的證明可能會用到抽象數學的知識,我不會555...)


那麼如何找原根?

考慮到最小的原根一般比較小,所以我們列舉,原根然後判斷。
假設我們當前列舉到\(i\),判斷的時候只需要列舉\(\varphi(p)\)的質因子\(p1,p2,p3...pk\)。然後判斷\(i^{\frac{\varphi(p)}{pj}}\)是不是全部都不是1,如果全部都不是1,\(i\)就是\(p\)的一個原根。
為什麼?
我們這個過程其實是列舉\(\varphi(p)\)的約數,因為i的階是\(\varphi(p)\)的一個約數(這個結論的1證明跟階的性質1證明差不多,可以自己證證),我們只需要看有沒有一個小於\(\varphi(p)\)的約數就能判斷i是不是原根了。
那為什麼不直接列舉約數,這樣列舉對嗎?
小於\(\varphi(p)\)的約數至少缺少一個質因子,因為如果\(x^a\equiv 1\)那麼\(x^{ab}\equiv 1\)少多個質因子的情況被少一個質因子的情況包含,所以列舉所有少掉一個質因子的情況即\(\frac{\varphi(p)}{pj}\)就行。


解高次同餘方程的步驟

首先要會BSGS和exgcd
\(x^a\equiv b(mod\ p)\)
1:先求出\(p\)的一個原根\(g\)
2:求出以\(g\)為底的b關於模p的指數r,即\(g^r\equiv b(mod\ p)\)(離散對數,用BSGS求解)
3:令\(x\equiv g^y(mod\ p)\),帶回原式就是求\(g^{ay} \equiv g^r(mod\ p)\)
4:根據階的性質3就是求\(ay\equiv r(mod\ p)\)(一次同餘方程用exgcd求解)
5:在0~\(\varphi(p)-1\)中求得y的解,帶回\(x\equiv g^y(mod\ p)\)解完方程。

有些值得注意的點:

因為原根的性質1求出的答案沒有重複。
為什麼要用原根代換b,別的數不行嗎?我們需要用原根表示b。見原根的性質1
因為要求原根且p為質數所以試用的p的範圍很小,見原根的性質3
只要求求出通解的複雜度為\(O(\sqrt p)\)
下面是輸出所有解得程式碼。。。

#include<bits/stdc++.h>
using namespace std;
#define int long long
const int N=201010;
unordered_map<int,int> hsh;
int prime[N],tot,T,phi,ans[N],num,a,b,p,g,x,y;
int read(){
    int sum=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
    return sum*f;
}
void work(int x){
    int tmp=x;
    tot=0;
    for(int i=2;i*i<=x;i++){
        if(tmp%i==0){
            prime[++tot]=i;
            while(tmp%i==0)tmp/=i;
        }
    }
    if(tmp>1)prime[++tot]=tmp;
}
int ksm(int x,int b){
    int tmp=1;
    while(b){
        if(b&1)tmp=tmp*x%p;
        b>>=1;
        x=x*x%p;
    }
    return tmp;
}
int BSGS(int a,int b){
    hsh.clear();
    int block=sqrt(p)+1;
    int tmp=b;
    for(int i=0;i<block;i++,tmp=tmp*a%p)hsh[tmp]=i;
    a=ksm(a,block);
    tmp=1;
    for(int i=0;i<=block;i++,tmp=tmp*a%p){
        if(hsh.count(tmp)&&i*block-hsh[tmp]>=0)return i*block-hsh[tmp];
    }
}
int exgcd(int &x,int &y,int a,int b){
    if(b==0){
        x=1;y=0;
        return a;
    }
    int gcd=exgcd(x,y,b,a%b);
    int z=x;
    x=y;y=z-(a/b)*y;
    return gcd;
}
signed main(){
    T=read();
    while(T--){
        p=read(),a=read(),b=read();
        b%=p;
        phi=p-1;
        work(phi);
        for(int i=1;i<=p;i++){
            bool flag=false;
            for(int j=1;j<=tot;j++)if(ksm(i,phi/prime[j])==1){flag=true;break;}
            if(flag==false){g=i;break;}
        }
        int r=BSGS(g,b);
        int gcd=exgcd(x,y,a,phi);
        if(r%gcd!=0){printf("No Solution\n");continue;}
        x=x*r/gcd;
        int k=phi/gcd;
        x=(x%k+k)%k;
        num=0;
        while(x<phi){ans[++num]=ksm(g,x),x+=k;}
        sort(ans+1,ans+1+num);
        for(int i=1;i<=num;i++)printf("%lld ",ans[i]);
        printf("\n");
    }
    return 0;
}

二次同餘方程

p為素質數至於為什麼要有素,接著看就知道了)
\(x^2\equiv A(mod\ p)\)

一些引理

引理1:x有正整數解的充要條件是\(A^{\frac{p-1}{2}} \equiv 1(mod \ p)\)
證明:
由費馬小定理得
\[ A^{p-1} \equiv 1(mod \ p)\]
\[A^{p-1}-1 \equiv 0(mod\ p)\]
\[(A^{\frac{p-1}{2}}+1)+(A^{\frac{p-1}{2}}-1) \equiv 0 \Rightarrow A^{\frac{p-1}{2}}\equiv \pm1(mod \ p)\]
\(x^2 \equiv A(mod\ p)\)\(A^{\frac{p-1}{2}} \equiv x^{p-1}(mod \ p)\)
由費馬小定理
\[x^{p-1} \equiv 1(mod\ p)\]
\[A^{\frac{p-1}{2}}\equiv 1(mod \ p)\]
證畢。
推論:x無正整數解的時\(A^{\frac{p-1}{2}} \equiv -1(mod \ p)\)
引理2:一共只有\((p-1)/2\)(不考慮0)個數存在模\(p\)意義下的二次方根,對於其中的每個數都存在兩個互為相反數的解。
證明:
假設有兩個數u,v,\(u^2-v^2 \equiv 0(mod\ p)\)那麼\((u+v)*(u-v) \equiv 0 (mod\ p)\),因為u,v\(\subset [1,p-1]\)(不考慮0),所以\(-p+1\leq u-v\leq p-1\)無法被\(p\)整除,所以\(u+v \equiv 0(mod\ p)\)
所以u,v互為相反數且對應唯一一個A,反過來也一樣。因為不考慮0且p為奇數,這樣的數有\(\frac{p-1}{2}\)對,且對應著\(\frac{p-1}{2}\)個A。
證畢。
此時我們就可以有一個解法。

解法一

1:我們求出\(p\)的一個原根\(g\)。然後求出以\(g\)為底的A關於模p的指數r,即\(g^r\equiv A(mod\ p)\)(離散對數,用BSGS求解)
2:\(A\)滿足\(A^{\frac{p-1}{2}}\equiv1(mod\ p)\)帶入得\(g^{\frac{r(p-1)}{2}}\equiv 1(mod\ p)\)由原根的定義得\(p-1 \mid \frac{r(p-1)}{2} \Rightarrow r \mid 2\)。然後\(g^{\frac{r}{2}}\)就是一個解,因為\(r\mid2\)所以可以直接快速冪,另一個解就是相反數。


又一些引理

定義:\(x^2 \equiv n (mod\ p)\)有解就說n是模p意義下的一個二次剩餘,無解就叫n是模p意義下的一個非二次剩餘。
然後就是一個非常神的推導。
我們定義設a滿足\(w=a^2-n\)是一個非二次剩餘。
引理3\((a+\sqrt{w})^p \equiv a-\sqrt{w}(mod \ p)\)
證明:
\((a+\sqrt{w})^p\)用二項式定理展開為\(\sum_{j=0}^p C_p^ja^jw^{p-j}\)。因為p是一個質數所以當\(j!=0且j!=p\)\(C_p^j\)都為\(0\)否則為1,因為分子中有\(p\)消不掉最後\(mod\ p\)得0。那麼\((a+\sqrt{w})^p \equiv a^p+\sqrt{w}^p\equiv a^{p-1}*a+w^{\frac{p-1}{2}}*\sqrt{w}(mod\ p)\)由費馬小定理和引理1的推論(別忘了w是一個非二次剩餘)最後化簡為\(a-\sqrt{w}\)
推導
\[(a+\sqrt{w})^{p+1}=(a+\sqrt{w})^{p}*(a+\sqrt{w})\]
\[=(a-\sqrt{w})(a+\sqrt{w})\]
\[=a^2-w\]
\[=a^2-(a^2-n)\]
\[=n\]
然後我們隨機一個\(a\)滿足條件,\(x\equiv (a+\sqrt{w})^{\frac{p+1}{2}}(mod\ p)\)根據拉格朗日定理可得答案中w的係數必然為0,就可以解得\(x\)了,又因為引理2所以期望隨機次數為2。複雜度可以保證。