數論內容簡要整理


部分內容引自清華大學秦岳《初等數論》,dengyaotriangle的博客_WZT_ 的博客niiick的博客超十一維的博客




算術基本定理

任何一個大於1的自然數$N$,如果$N$不為質數,那么$N$可以唯一分解成有限個質數的乘積

$$N=P_1^{a_1}*P_2^{a_2}*P_3^{a_3}......P_n^{a_n}$$

這里$P1<P2<P3......<Pn$均為質數,其中指數$a_i$是正整數。這樣的分解稱為$N$的標准分解式

素數無限定理

正整數集中包含無限個素數

證明:假設素數有限,設其為$p_1...p_n$,構造$s=1+\prod p_i$,若s是素數,矛盾;若s是合數,則$p_1...p_n$都不是s的約數,與算術基本定理矛盾

Eratosthnes素數篩法

設置一從2開始的數表,若該數沒有被划掉,則其為一個素數,將其所有倍數划掉

復雜度$O(nlogn)$

優化版埃氏篩關鍵部分代碼

p[1]=1;    //bool p[i]表示i是否為素數
int sq=sqrt(n);
for(int i=2;i<=sq;i++)
    if(!p[i])
        for(int j=i*i;j<=n;j+=i)
            p[j]=1;
View Code


歐拉線性篩法

維護每個數的最小素因子$mindiv$,從2開始,若其$mindiv$未知,則為素數,將其小於本身$mindiv$的素數倍的數設置成素數。每個數只會被其最小素因子篩一次。復雜度$O(n)$

線性篩關鍵部分代碼

p[1]=1;
for(int i=2;i<=n;i++)
{
    if(!p[i])
        pr[++cnt]=i;    //pr為素數表
    for(int j=1;j<=cnt&&pr[j]*i<=n;j++)
    {
        p[i*pr[j]]=1;
        //以pr[j]作為最小質因子更新p[i*pr[j]]
        if(i%pr[j]==0)
            break;
        /*i的mindiv比pr[j]更小,最小質因子不再是pr[j]
        ,若繼續更新則會出現冗余操作*/
    }
}
View Code


利用線性篩實現的高效分解質因數

對於數$x$每次取其最小質因子,更新$x$為$x/mindiv$,當$x=1$時分解結束,時間復雜度$O(logn)$

s[1]=1;
for(int i=2;i<=n;i++)
{
    if(!s[i])
        p[++cnt]=i,g[i]=cnt;
    for(int j=1;j<=cnt&&i*p[j]<=n;j++)
    {
        s[i*p[j]]=1,g[i*p[j]]=j;
        if(i%p[j]==0)
            break;
    }
}
View Code


朴素分解質因數

$O(\sqrt n)$的分解質因數,對於單個數的分解質因數和積性函數單值求解具有重要作用

for(int i=2;i*i<=n;i++)
    while(n%i==0)
    //這里的i一定是素數,不妨利用反證法證明
    //若i為合數,設i有素因子j小於i,j在前面的過程中已被篩去,n%j!=0故n%i!=0,與條件矛盾,故i必為素數
        n/=i;
View Code


更相減損術

$gcd(a,b)=gcd(a,a-b)$

歐幾里得算法

$gcd(a,b)=gcd(b,a\%b)$

裴蜀定理(貝祖定理)

若$a,b$是整數,且$(a,b)=d$,那么對於任意的整數$x,y$,$ax+by$都一定是$d$的倍數,特別地,一定存在整數$x,y$,使$ax+by=d$成立。

推論:$a,b$互質的充要條件是存在整數$x,y$使$ax+by=1$

推論:設$a_1,a_2,a_3......a_n$為$n$個整數,$d$是它們的最大公約數,那么存在整數$x_1......x_n$使得$x_1*a_1+x_2*a_2+...x_n*a_n=d$

擴展歐幾里得算法(exgcd)

$exgcd$用於解決二元一次不定方程的解的相關問題

對於不定方程$ax+by=c$

由裴蜀定理可知$gcd(a,b)|(ax+by)$,故若$c$不是$gcd(a,b)$的倍數則無整數解

引理:$ax+by=gcd(a,b)$的特解求法

顯然存在$x1,y1$使得$ax+by=bx_1+(a\%b)y_1$成立

由模運算的性質可知$a\%b=a-b*\left\lfloor\dfrac{a}{b}\right\rfloor$

可得$ax+by=bx_1+(a-b*\left\lfloor\dfrac{a}{b}\right\rfloor)y_1$

$=ay_1+b*(x_1-\left\lfloor\dfrac{a}{b}\right\rfloor y_1)$

則有$x=y_1,y=x_1-\left\lfloor\dfrac{a}{b}\right\rfloor y_1$

由歐幾里得算法得迭代過程的終止狀態為$a=gcd(a,b),b=0$

此時有$gcd(a,b)*x=gcd(a,b)$,取$x=1$即可,此時任取$y$均可保證該式成立,為避免溢出常取$y=0$

該過程的代碼實現

void exgcd(int a,int b,int &x,int &y)
{
    if(!b)
    {
        x=1,y=0;
        return;
    }
    exgcd(b,a%b,y,x);
    y-=x*(a/b);
}
View Code


設$x_0,y_0$為$ax+by=gcd(a,b)$的一組特解,即有$ax_0+by_0=gcd(a,b)$

則有原方程的一組特解

$$a\frac{x_0c}{gcd(a,b)}+b\frac{y_0c}{gcd(a,b)}=c$$

$$x_1=\frac{x_0c}{gcd(a,b)},y_1=\frac{y_0c}{gcd(a,b)}$$

構造原方程的通解形式

易得對於任意常數$d$,有$a(x_1+db)+b(y_1-da)=c$成立。為保證通解均為整數解,只需使$db,da$均為整數即可;而為保證得到通解,$d$須取滿足上述條件的最小值,而易得該最小值為$\frac{1}{gcd(a,b)}$

可得通解:$x=x_1+\frac{kb}{gcd(a,b)},y=y_1+\frac{ka}{gcd(a,b)}$其中$k$為任意整數

並有性質:隨$k$增大,$x$增大,$y$減小

則有最小正整數解$(x\%d_x+d_x)\%d_x$($d_x$為上文所提$db$)(若上式結果為0則最小正整數解為$d_x$),此時$y$取到兩數均為正整數時的最大值

乘法逆元

$ab≡ba≡1(mod\ p)$
則稱$b$是$mod\ p$意義下$a$的乘法逆元(定義了剩余系中的除法),記為$a^{-1}$,$a$的乘法逆元的意義是$a$在$mod\ p$剩余系下的倒數

乘法逆元的擴展歐幾里得求法

給定$a,p$計算$b$使得$a*b≡1(mod\ p)$,等價於解方程$ax+py=1$($x,y$為整數變量,擴展歐幾里得即可)

條件:$a,p$互質,即二元一次不定方程有解的條件,也即乘法逆元存在的充要條件

if(exgcd(a,mod,x,y)==1)    //判斷逆元是否存在
    printf("%d\n",(x%mod+mod)%mod);    //xj=即為a的逆元
View Code


時間復雜度$O(logn)$

費馬小定理

假如$p$是質數,且$gcd(a,p)=1$,那么$a^{p-1}≡1(mod\ p)$

證明:

引理:集合$S1=\{1,2,3…p-1\},S2=\{1a,2a,3a…(p-1)a\}$,$S1$在模$p$意義下等於$S2$

故$(p-1)!≡a^{p-1}*(p-1)! (mod\ p)$,$(p-1)!$與$p$互素存在乘法逆元,故$a^{p-1}≡1(mod\ p)$。

乘法逆元的快速冪求法

若$p$是素數,由於$a^{p-1}≡1(mod\ p)$,故$a$的乘法逆元為$a^{p-2}$(就一個快速冪,所以這里就不再提供代碼了)

條件:$a,p$互質且$p$為質數;時間復雜度:$O(logn)$

線性預處理乘法逆元

在$O(n)$的時間內求出$1..n$的逆元,條件:$1...n$均與$p$互素(為簡化表達常表達為$p$為質數)

顯然$1^{-1}≡1(mod\ p)$

設$p=\left\lfloor\dfrac{p}{k}\right\rfloor*k+r(0<r<k<p)$

可得$\left\lfloor\dfrac{p}{k}\right\rfloor*k+r≡0(mod\ p)$

兩邊同乘$k^{-1},r^{-1}$可得

$\left\lfloor\dfrac{p}{k}\right\rfloor*r^{-1}+k^{-1}≡0(mod\ p)$

可得$k^{-1}≡-\left\lfloor\dfrac{p}{k}\right\rfloor*(p\ mod\ k)^{-1}(mod\ p)$

由此可以實現遞推求解逆元

a[1]=1;
for(int i=2;i<=n;i++)
{
    a[i]=-(p/i)*a[p%i];
       a[i]=(a[i]%p+p)%p;
}
View Code


積性函數

在數論中的積性函數:對於正整數$n$的一個算術函數$f(n)$,若$f(1)=1$,且當$a,b$互質時$f(ab)=f(a)f(b)$,在數論上就稱它為積性函數。若對於某積性函數$f(n)$,就算$a,b$不互質,也有$f(ab)=f(a)f(b)$,則稱它為完全積性的。

歐拉函數

對正整數$n$,歐拉函數$\varphi(n)$是小於等於$n$的正整數中與$n$互質的數的數目,例如$\varphi(8)=4(1,3,5,7)$

由歐拉函數的積性可得$φ(n)=\prodφ(p_i^{q_i})$

$φ(x=p^q)=p^{q-1}*(p-1)=x*(1-\frac{1}{p})$($p$為質數)
這個結論是顯然的。

故$φ(x)=x*\prod\limits_{i=1}^n(1-\frac{1}{p_i})$

由$φ$的積性性質可由線性篩法$O(n)$計算$φ(1)...φ(n)$

p[1]=1,phi[1]=1;
for(int i=2;i<=maxn-10;i++)
{
    if(!p[i])
        pr[++cnt]=i,phi[i]=i-1;
    for(int j=1;j<=cnt&&pr[j]*i<=maxn-10;j++)
    {
        p[i*pr[j]]=1;
        if(i%pr[j]==0)
        {
            phi[i*pr[j]]=phi[i]*pr[j];
            break;
        }
        phi[i*pr[j]]=phi[i]*phi[pr[j]];
    }
}
View Code


歐拉定理

若$p,a$為正整數,且$p,a$互質,則:$a^{φ(p)}≡1(mod\ p)$

推論:$(a^{φ(p)})^{-1}=a^{φ(p)}$

推論:$a^b≡a^{b\%φ(p)}≡a^{b-k*φ(p)}(gcd(a,p)=1)$(等式兩邊同乘$(a^{φ(p)})^{-1}$)

擴展歐拉定理


$a^b≡\begin{cases}a^b,b<\varphi(p)\\a^{b\ mod\ \varphi(p)+\varphi(p)},b\geqslant\varphi(p)\end{cases}\pmod p$

不要求$a,p$互質


中國剩余定理(CRT)

中國剩余定理可用於求解同余方程組

$\begin{cases}x≡a_1(mod\ m_1)\\x≡a_2(mod\ m_2)\\.....\\x≡a_n(mod\ m_n)\end{cases}$

其中$m_1,m_2...m_n$為兩兩互質的整數

求解過程:

我們設$M=\prod\limits_{i=1}^nm_i\ ,\ M_i=\frac{M}{m_i}\ ,\ M_it_i≡1(mod\ m_i)\ (1<=i<=n)$

則該方程組必有一解$x_0=\sum\limits_{i=1}^na_iM_it_i$

可得通解$x=x_0+k*M$($k$為任意整數)

則有最小正整數解$x_{min}=(x\%M+M)\%M$,上式結果為0時$x_{min}=M$

證明:

$\begin{cases}a_jM_jt_j≡0(mod\ m_i)(i\ne j)\\a_jM_jt_j≡a_j(mod\ m_i)(i=j)\end{cases}$

故$\sum\limits_{i=1}^na_iM_it_i≡a_i(mod\ m_i)$

擴展中國剩余定理(EXCRT)

擴展中國剩余定理可用於求解同余方程組

$\begin{cases}x≡a_1(mod\ m_1)\\x≡a_2(mod\ m_2)\\.....\\x≡a_n(mod\ m_n)\end{cases}$

和中國剩余定理的區別在於,擴展中國剩余定理不要求$m_i$兩兩互質(很強的性質)

考慮遞推求解,假設已經求出前$k-1$個方程組成的同余方程組的一個解$x$,設$M=lcm(m_1,m_2...m_{k-1})$

則前$k-1$的方程的通解為$x+i*M$($i$為任意整數)

那么對於加入第$k$個方程后的方程組

我們就是要求一個正整數$t$,使得$x+t*M≡a_k(mod\ m_k)$

即$t*M≡a_k-x(mod\ m_k)$

對於這個式子我們已經可以通過擴展歐幾里得求解$t$

若該同余式無解,則整個方程組無解,若有,則前$k$個同余式組成的方程組的一個解為$x_k=x+t*M$

核心代碼

scanf("%lld%lld%lld",&n,&a,&b);
m=a,ans=b;
for(int t,tmp,i=2;i<=n;ans%=m,i++)
{
    scanf("%lld%lld",&a,&b);
    int g=exgcd(m,a,t,tmp),c=((b-ans)%a+a)%a;
    if(c%g)
    {
        printf("-1\n");
        return 0;
    }
    t=mul(t,c/g,a/g),ans+=t*m,m=lcm(m,a);
}
ans=(ans%m+m)%m;
printf("%lld\n",ans?ans:m);
View Code


大步小步算法(BSGS)

$BSGS$主要用於求解形如$a^x≡b(mod\ p)$的方程,其中$gcd(a,p)=1$

考慮最小解$x_0$,由歐拉定理的推論可得$a^x≡a^{x-k*φ(p)}$,則$x_0\in[0,φ(p)),k\in Z$

設$a^{x=ik-t}≡b(mod\ p)$,則必有$a^{ik}≡b*a^t(mod\ p)(0<t<=k,0<i<=\left\lceil\dfrac{φ(p)}{k}\right\rceil)$

枚舉$t$,將$b*a^t\%p$存入哈希表(這里也可以使用$map$,不過會多帶一個$log$),枚舉$i$,在哈希表中查找即可得到第一個循環節中的所有解。第一個查找到的解即為最小解,對於第一個循環節中的任一解$x$,顯然$x+k*φ(p),k\in Z^*$為該方程的解

時間復雜度$O(k+\dfrac{φ(p)}{k})$,由均值不等式可得$k=\sqrt{φ(p)}$時有最低時間復雜度$O(\sqrt{φ(p)})$

最小解求解代碼

k=ceil(sqrt(phi));
int tp=1;
for(int tmp=n*b%p,i=1;i<=k;i++,(tp*=b)%=p,(tmp*=b)%=p)
    mp[tmp]=i;
for(int tmp=tp,i=1;i<=(phi+k-1)/k;i++,(tmp*=tp)%=p)
    if(mp[tmp])
    {
        printf("%lld\n",i*k-mp[tmp]);
        return 0;
    }
printf("no solution\n");
View Code


擴展BSGS

擴展$BSGS$主要用於求解形如$a^x≡b(mod\ p)$的方程

對於同余方程$a^x≡b(mod\ p)$,我們可以將其展開為$a*a^{x-1}+pk=b$的形式,可得$gcd(a,p)|b,x>0$為原方程有整數解的一個充分條件,這時討論$x=0$等式是否成立,若成立則求得答案,否則若方程無解則同余方程無解

對於有解的方程,兩邊同除$gcd(a,p)$可得$\frac{a}{gcd(a,p)}*a^{x-1}+\frac{p}{gcd(a,p)}*k=\frac{b}{gcd(a,p)}$

轉化為同余式可得$\frac{a}{gcd(a,p)}a^{x-1}≡\frac{b}{gcd(a,p)}(mod\ \frac{p}{gcd(a,p)})$

設$p'=\frac{p}{gcd(a,p)}$,若$gcd(a,p')=1$,按$BSGS$處理即可,否則重復執行上述過程

顯然遞歸深度不超過$logp$,故可近似認為擴展$BSGS$與$BSGS$時間復雜度相同

完整代碼

 

#include<iostream>
#include<cstdio>
#include<cmath>
#include<map>
#define int long long
using namespace std;
int c,a,p,b,k,ans,phi;
map<int,int>mp;
int gcd(int x,int y)
{
    return y?gcd(y,x%y):x;
}
signed main()
{
    while(1)
    {
        scanf("%lld%lld%lld",&a,&p,&b);
        if(!a)
            return 0;
        a%=p,mp.clear(),ans=0,c=1;
        int ps=p,bs=b;
        bool f=0;
        if(b>=p)
        {
            printf("No Solution\n");
            continue;
        }
        if(!a)
        {
            printf("0\n");
            continue;
        }
        for(int g=gcd(a,p);g!=1;g=gcd(a,p))
        {
            if(c==b)
            {
                printf("%lld\n",ans),f=1;
                break;
            }
            if(b%g)
            {
                printf("No Solution\n"),f=1;
                break;
            }
            p/=g,(c*=a/g)%=p,b/=g,ans++;
        }
        if(f)
            continue;
        phi=p;
        for(int tmp=p,i=2;i*i<=tmp;i++)
            if(tmp%i==0)
            {
                while(tmp%i==0)
                    tmp/=i;
                phi=phi*(i-1)/i;
            }
        k=ceil(sqrt(phi));
        int tp=1;
        for(int tmp=b*a%p,i=1;i<=k;i++,(tp*=a)%=p,(tmp*=a)%=p)
            mp[tmp]=i;
        for(int tmp=tp,i=1;i<=(phi+k-1)/k;i++,(tmp*=tp)%=p)
            if(mp[tmp*c%p])
            {
                printf("%lld\n",i*k-mp[tmp*c%p]+ans),f=1;
                break;
            }
        if(!f)
            printf("No Solution\n");
    }
    return 0;
}
View Code

 

階和原根

定義:

階:若$p,a$為正整數,且$p,a$互質,稱滿足同余式$a^x \equiv 1 \pmod p$的最小正整數$x$作$a$模$p$的階,記作$ord_pa$

原根:若$p,a$為正整數,且$p,a$互質,且$ord_pa=\varphi(p)$,則稱$a$為模$p$的原根

階的性質:

1,$a^n≡1(mod\ p)$的充要條件為$\mathrm{ord}_pa|n$

推論:$ord_pa∣φ(p)$

2,對正整數$b$,若$a\equiv b\pmod p$,則$\text{ord}_pa=\text{ord}_pb$

3,設$m,n\in\mathbb N$,$a^m\equiv a^n\pmod p$的充要條件為 $m\equiv n\pmod {\text{ord}_pa}$

4,令$\text{ord}_pa=x$,則$1,a,a^2,\cdots,a^{x-1}$,模$p$兩兩不同余

5,對正整數$b$,若$ab\equiv1\pmod p$,則$\text{ord}_pa=\text{ord}_pb$

6,令$x=\text{ord}_pa$,對正整數$t$有$\text{ord}_pa^t=\frac{x}{\gcd(t,x)}$

7,對正整數$m$,若$m\mid p$,則$\text{ord}_ma\mid \text{ord}_pa$

8,對正整數$m$,若$m\bot p,a\bot m$,則 $\text{ord}_{mp}a=\text{lcm}(\text{ord}_{m}a,\text{ord}_{p}a)$

9,對正整數$b$,若$b\bot p$且$\mathrm{ord}_pa\bot \mathrm{ord}_pb$,則$\mathrm{ord}_pab=\mathrm{ord}_pa\times \mathrm{ord}_pb$

原根存在定理

原根存在的充要條件:模數為$2,4,p^k,2\times p^k$,其中$p$為奇素數,$k$為正整數

原根判定定理

$a$為模$m$的原根的充要條件是對於$\varphi(m)$的任意質因子$p$,必有 $a^{\frac{\varphi(m)}{p}}\not\equiv 1 \pmod m$,且$a^{\varphi(m)} \equiv 1 \pmod m$。

證明:由階的性質1及其推論可得

原根的性質

1,設$a$為模$p$的原根,則集合$S=\{a^{s} \mid 1 \leq s \leq \varphi(p),s\bot\varphi(p)\}$給出模$p$的全部兩兩不同余的原根。模$p$的全部兩兩不同余的原根有 $\varphi(\varphi(p))$個。

2,最小原根是不大於$p^{\frac{1}{4}}$級別的

原根的求解

基於原根的性質,設計以下算法:依據原根判定定理枚舉求解最小原根$a$;枚舉指數$s$,若$s$與$\varphi(p)$互質,則$a^s\ mod \ p$為一個原根

完整代碼

#include<iostream>
#include<cstdio>
#include<algorithm>
#define int long long
using namespace std;
const int maxn=1e6+10;
int t,n,phi[maxn],pr[maxn],g[maxn],cnt,ord[maxn];
bool p[maxn],f[maxn];
int gcd(int x,int y)
{
    return y?gcd(y,x%y):x;
}
int quick_pow(int x,int y)
{
    int ret=1;
    for(;y;y>>=1,(x*=x)%=n)
        if(y&1)
            (ret*=x)%=n;
    return ret;
}
bool check(int x)
{
    for(int i=phi[n];i>1;i/=g[i])
        if(quick_pow(x,phi[n]/g[i])==1)
            return 0;
    return 1;
}
signed main()
{
    p[1]=1,phi[1]=1;
    for(int i=2;i<=maxn-10;i++)
    {
        if(!p[i])
            pr[++cnt]=i,phi[i]=i-1,g[i]=i;
        for(int j=1;j<=cnt&&pr[j]*i<=maxn-10;j++)
        {
            p[i*pr[j]]=1,g[i*pr[j]]=pr[j];
            if(i%pr[j]==0)
            {
                phi[i*pr[j]]=phi[i]*pr[j];
                break;
            }
            phi[i*pr[j]]=phi[i]*phi[pr[j]];
        }
    }
    f[2]=f[4]=1;
    for(int i=2;i<=cnt;i++)
        for(int j=pr[i];j<=maxn-10;j*=pr[i])
        {
            f[j]=1;
            if(2*j<=maxn-10)
                f[2*j]=1;
        }
    scanf("%lld",&t);
    while(t--)
    {
        scanf("%lld",&n);
        if(!f[n])
        {
            printf("0\n\n");
            continue;
        }
        int a=1,tot=1;
        for(;!check(a)||quick_pow(a,phi[n])!=1;a++);
        ord[1]=a;
        for(int i=2;i<phi[n];i++)
            if(gcd(i,phi[n])==1)
                ord[++tot]=quick_pow(a,i);
        sort(ord+1,ord+tot+1);
        printf("%lld\n",tot);
        for(int i=1;i<=tot;i++)
            printf("%lld ",ord[i]);
        printf("\n");
    }
    return 0;
}
View Code

 

二次剩余

定義

二次剩余,俗稱模意義開根,這里只介紹模數$p$為奇素數的解法

對於正整數$n$,若對於一個奇素數$p$,存在$x$滿足$x^2\equiv n(mod \ p)$則稱$n$是模$p$的二次剩余,否則稱$n$是模$p$的非二次剩余

二次剩余的性質

1,對於模$p$的二次剩余$n$,該方程有兩個不同解,且它們互為模意義下的相反數

2,任意一對相反數都對應一個二次剩余,而且這些二次剩余是兩兩不同的

3,二次剩余的數量恰為$\frac{p-1}{2}$,其他的非$0$數都是非二次剩余,數量也是$\frac{p-1}{2}$

4,二次剩余的逆元還是二次剩余,兩個二次剩余的乘積還是二次剩余

歐拉准則

1,$n^{\frac{p-1}{2}} \equiv 1$與$n$是二次剩余等價

2,$n^{\frac{p-1}{2}} \equiv -1$與$n$是非二次剩余等價

$Cipolla$算法

首先找到一個$a$滿足$a^2 - n$是非二次剩余,由於非二次剩余的數量是$\frac{p-1}{2}$,通過隨機+根據歐拉准則檢驗的方式期望約$2$次可以找到這樣一個$a$。

接下來定義$i^2 \equiv a^2 - n$。

但是$a^2 - n$不是二次剩余,怎么找得到這樣一個$i$?

類比實數域到復數域的推廣,定義這樣一個$i$,將所有數表示為$A+Bi$的形式,
其中$A, B$都是模$p$意義下的數,類似於實部和虛部。

考慮證明$(a + i)^{p+1} \equiv n$

引理 1 :$i^p \equiv -i$

證明:$i^p \equiv i(i^2)^{\frac{p-1}{2}} \equiv i(a^2 - n)^{\frac{p-1}{2}} \equiv -i$

引理 2 :$(A + B)^p \equiv A^p + B^p$

證明:二項式定理展開后,由於$p$是質數,除了$C_p^0, C_p^p$外的組合數分子上的階乘沒法消掉,模$p$都會為$0$,剩下來的就是$C_p^0 A^0 B^p + C_p^p A^p B^0$

現在根據上述引理和費馬小定理完成證明:

$(a + i)^{p+1} \equiv (a^p + i^p) (a + i) \equiv (a - i) (a + i) \equiv a^2 - i^2 \equiv n$

可以證明$(a + i)^{\frac{p+1}{2}}$的虛部一定為$0$,那么$(a + i)^{\frac{p+1}{2}}$即是一個解,其相反數是另一個解。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<ctime>
#define int long long
using namespace std;
struct c{
    int x,y;
};
int t,n,p,a,pw;
int mod(int x)
{
    return (x%p+p)%p;
}
c operator *(c &x,const c &y)
{
    return (c){mod(x.x*y.x+pw*x.y%p*y.y),mod(x.x*y.y+y.x*x.y)};
}
int quick_pow(c x,int y)
{
    c ret;ret.x=1,ret.y=0;
    for(;y;y>>=1,x=x*x)
        if(y&1)
            ret=ret*x;
    return ret.x;
}
int pow(int x,int y)
{
    int ret=1;
    for(;y;y>>=1,(x*=x)%=p)
        if(y&1)
            (ret*=x)%=p;
    return ret;
}
signed main()
{
    srand(time(0));
    scanf("%lld",&t);
    while(t--)
    {
        scanf("%lld%lld",&n,&p);
        if(pow(n,(p-1)/2)==p-1)
        {
            printf("Hola!\n");
            continue;
        }
        else if(!n)
        {
            printf("0\n");
            continue;
        }
        for(a=rand()%p;pow(pw=mod(a*a-n),(p-1)/2)!=p-1;a=rand()%p);
        int ans=quick_pow((c){a,1},(p+1)/2);
        if(p-ans<ans)
            ans=p-ans;
        printf("%lld %lld\n",ans,p-ans);
    }
    return 0;
}
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM