首页 > 技术文章 > [ural1132]Square Root(cipolla算法)

elpsycongroo 2017-11-17 18:33 原文

题意:求${x^2} \equiv n\bmod p$

解题关键:

定理:若$a$满足$w = {a^2} - n$是模$p$的二次非剩余,即,${x^2} = w\bmod p$无解,则${(a + \sqrt w )^{\frac{{p + 1}}{2}}}$是二次剩余方程${x^2} \equiv n\bmod p$的解。

证明:

$\begin{array}{l}
{x^2} \equiv {(a + \sqrt w )^{p + 1}} \equiv (a + \sqrt w ){(a + \sqrt w )^p}\\
\equiv (a + \sqrt w )(\sum {C_p^i{a^{p - i}}{w^{\frac{i}{2}}}} )\\
\equiv (a + \sqrt w )({a^p} + {w^{\frac{{p - 1}}{2}}}\sqrt w )\\
\equiv (a + \sqrt w )(a - \sqrt w )\\
\equiv n(\bmod p)
\end{array}$

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cstdlib>
#include<iostream>
#include<cmath>
using namespace std;
typedef long long ll;
ll w,a,x,p,T;
struct CN{
    ll x,y;
    CN friend operator *(CN x,CN y){
        CN z;
        z.x=(x.x*y.x+x.y*y.y*w)%p;
        z.y=(x.x*y.y+x.y*y.x)%p;
        return z;
    }
};

CN Cmod_pow(CN x,ll n){
    CN z={1,0};
    while(n){
        if(n&1)z=z*x;
        x=x*x;
        n>>=1;
    }
    return z;
}

ll mod_pow(ll x,ll n,ll p){
    ll res=1;
    while(n){
        if(n&1) res=res*x%p;
        x=x*x%p;
        n>>=1;
    }
    return res;
}

int main(){
    scanf("%lld",&T);
    while(T--){
        scanf("%lld%lld",&x,&p);
        x%=p;
        if(p==2){
            printf("1\n");
            continue;
        }
        if(mod_pow(x,(p-1)/2,p)==p-1){
            printf("No root\n");
            continue;
        }
        while(1){
            a=rand()%p;
            w=(a*a-x+p)%p;
            if(mod_pow(w,(p-1)/2,p)==p-1) break;
        }
        
        CN u={a,1};
        u=Cmod_pow(u,(p+1)/2);
        ll yi=u.x,er=p-u.x;
        if(yi>er) printf("%lld %lld\n",er,yi);
        else if(yi==er) printf("%lld\n",yi);
        else printf("%lld %lld\n",yi,er);
    }
}

 

推荐阅读