二次剩余学习笔记

目录

  • 二次剩余学习笔记
    • 二次剩余
    • 勒让德符号
    • cipolla算法
    • 代码实现

二次剩余学习笔记

看SCOI2018的时候发现不会这个东西
来写模板与简单证明
p是奇质数,偶的就那一个,就不讨论了

二次剩余

求解\(x^2\equiv n \pmod p\)

勒让德符号

\(a^\frac{P-1}{2}\equiv \left(\frac{a}{p}\right) \pmod p\)

\(x^2\equiv a \pmod p\)
存在x时\(x^{p-1}\equiv 1 \pmod p\)
所以\(x\equiv a^{\frac{1}{2}}\pmod p\)\(x^{p-1}\equiv a^{\frac{p-1}{2}}\equiv 1\pmod p\)

不存在x时\(a^{\frac{p-1}{2}}\)不能被表示成\(x^{p-1}\) ,于是这个东西就不等于1,又因为它的平方等于1,所以它就等于-1(膜意义下)

cipolla算法

首先随机a使得\(a^2-n\)不是二次剩余
\(\omega =\sqrt{a^2-n}\),作为当前数域下单位根
由于满足一系列性质,这个数域是成立的

又因为\(\omega^2\)不是二次剩余,由勒让德符号可知\((w^2)^{\frac{p-1}{2}}\equiv w^{p-1}\not \equiv 1\pmod p\)
由费马小定理,\((w^2)^{p-1}\equiv 1 \pmod p\)
所以\(w^{p-1}\equiv -1\)

于是就可以搞事情了

有这样一个式子
\[ (a+w)^{p+1} \]

\[ \equiv(a+w)^p(a+w) \]

\[ \equiv(\sum_i a^iw^{p-i}C^i_p)(a+w) \pmod p \]

因为\(i!=p,0\)时组合数的阶乘p无法消掉(奇质数),所以\(mod~p\)之后为0
\[ \equiv (a^p+w^p)(a+w) \pmod p \]
由上面的结论和费马小定理:

\(w^{p-1}\equiv -1\)
\(a^{p-1}\equiv 1\)


\[ \equiv (a-w)(a+w) \pmod p \]

\[ \equiv a^2-w^2\pmod p \]

\[ \equiv a^2-(a^2-n)\pmod p \]

\[ \equiv n \pmod p \]

整理得到
\[ (x^2)\equiv (a+w)^{\frac{p+1}{2}*2}\equiv (a+w)^{p+1}\equiv n \pmod p \]
\(x \equiv \pm (a+w)^{\frac{p+1}{2}}\)

可以证明其不含\(w\)

代码实现

#include
#include
#include
#include
#include
#define ll long long 
using namespace std;
ll read(){
    ll x=0,pos=1;char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') pos=0;
    for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
    return pos?x:-x; 
}
ll mod,n;
ll i2;
struct complex{
    ll r,i;
    complex(ll r=0,ll i=0):r(r),i(i){}
    int operator == (complex y){
        return r==y.r&&i==y.i;
    }
    complex operator *(complex y){
        return complex((r*y.r%mod+i*y.i%mod*i2%mod)%mod,((r*y.i%mod+i*y.r)%mod)%mod); 
    }
}; 
complex ksm(complex a,int b){
    complex res=complex(1,0);
    while(b){
        if(b&1) res=res*a;
        a=a*a;
        b>>=1;
    }
    return res;
}
int check(int x){
    return ksm(complex(x,0),(mod-1)/2)==1;
}
int R(int now){
    return ((rand()<<15)+rand())%(now-1)+1;
} 
void solve(){
    ll a=R(mod);
    while(check((a*a+mod-n)%mod)) a=R(mod);
    i2=(a*a%mod-n+mod)%mod;
    ll x0=ksm(complex(a,1),(mod+1)/2).r;
    printf("%lld ",min(x0,mod-x0));
    printf("%lld\n",max(x0,mod-x0)); 
}
int main(){
    int T=read();
    while(T--){
        n=read(),mod=read();
        if(n==0){
            printf("%d\n",0);continue;
        }
        if(!check(n)) printf("Hola!\n");
        else solve();
    }
    return 0;
} 

你可能感兴趣的:(二次剩余学习笔记)